# Search Access Memberships Source: https://docs.serval.com/api-reference/access-membership-api/search-access-memberships /sections/api-reference/openapi-spec-v2.yaml post /v2/access-memberships/search List a user’s recorded Access Management role memberships within one team, matching the role Users rosters. Includes memberships recorded by provisioning, sync, or linked-group reconciliation. Does not query external applications or reconstruct standalone workflow effects. Requires membership-read permission on the team; workflow workers are restricted to their own team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `access-memberships:read` | | Team-scoped API key | `access-memberships:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Access Policy Source: https://docs.serval.com/api-reference/access-policy-api/create-access-policy /sections/api-reference/openapi-spec-v2.yaml post /v2/access-policies Create a new access policy for a team. A new policy has no approval procedure, so requests for roles governed by it proceed without approval until you attach one with Create Access Policy Approval Procedure. The Access Policy Approval Procedure API is the only way to manage a policy's procedure. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Access Policy Source: https://docs.serval.com/api-reference/access-policy-api/delete-access-policy /sections/api-reference/openapi-spec-v2.yaml delete /v2/access-policies/{id} Delete an access policy. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Access Policy Source: https://docs.serval.com/api-reference/access-policy-api/get-access-policy /sections/api-reference/openapi-spec-v2.yaml get /v2/access-policies/{id} Get a specific access policy by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Access Policies Source: https://docs.serval.com/api-reference/access-policy-api/list-access-policies /sections/api-reference/openapi-spec-v2.yaml get /v2/access-policies List all access policies for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Access Policy Source: https://docs.serval.com/api-reference/access-policy-api/update-access-policy /sections/api-reference/openapi-spec-v2.yaml put /v2/access-policies/{id} Update an existing access policy. Fields left out of the request keep their current values. This endpoint never changes the policy's approval procedure: the request has no approval-procedure field, and the attached procedure stays in place. To attach, replace, or remove a procedure, use the Access Policy Approval Procedure API. Only that API can remove one. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Access Policy Approval Procedure Source: https://docs.serval.com/api-reference/access-policy-approval-procedure-api/create-access-policy-approval-procedure /sections/api-reference/openapi-spec-v2.yaml post /v2/access-policies/{access_policy_id}/approval-procedures Create a new approval procedure for an access policy. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Access Policy Approval Procedure Source: https://docs.serval.com/api-reference/access-policy-approval-procedure-api/delete-access-policy-approval-procedure /sections/api-reference/openapi-spec-v2.yaml delete /v2/access-policies/{access_policy_id}/approval-procedures/{id} Delete an approval procedure for an access policy. Update Access Policy never detaches a procedure. Removing a policy's approval gate is always an explicit call on this API: this endpoint, or Update Access Policy Approval Procedure with no steps and no stages. After deletion, requests for roles governed by the policy proceed without approval until you create a new procedure. The deletion produces its own audit event. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Access Policy Approval Procedure Source: https://docs.serval.com/api-reference/access-policy-approval-procedure-api/get-access-policy-approval-procedure /sections/api-reference/openapi-spec-v2.yaml get /v2/access-policies/{access_policy_id}/approval-procedures/{id} Get a specific approval procedure by ID for an access policy. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Access Policy Approval Procedures Source: https://docs.serval.com/api-reference/access-policy-approval-procedure-api/list-access-policy-approval-procedures /sections/api-reference/openapi-spec-v2.yaml get /v2/access-policies/{access_policy_id}/approval-procedures List all approval procedures for an access policy. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Access Policy Approval Procedure Source: https://docs.serval.com/api-reference/access-policy-approval-procedure-api/update-access-policy-approval-procedure /sections/api-reference/openapi-spec-v2.yaml put /v2/access-policies/{access_policy_id}/approval-procedures/{id} Update an existing approval procedure for an access policy. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Remove the approval gate:** An empty steps list removes the gate. # Create Access Profile Source: https://docs.serval.com/api-reference/access-profile-api/create-access-profile /sections/api-reference/openapi-spec-v2.yaml post /v2/access-profiles Create a new access profile for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Access Profile Grant Source: https://docs.serval.com/api-reference/access-profile-api/create-access-profile-grant /sections/api-reference/openapi-spec-v2.yaml post /v2/access-profile-grants Attach an access profile to a workflow, app resource role, or form. One grant per profile-resource pair. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Access Profile Source: https://docs.serval.com/api-reference/access-profile-api/delete-access-profile /sections/api-reference/openapi-spec-v2.yaml delete /v2/access-profiles/{id} Delete an access profile. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Access Profile Grant Source: https://docs.serval.com/api-reference/access-profile-api/delete-access-profile-grant /sections/api-reference/openapi-spec-v2.yaml delete /v2/access-profile-grants/{id} Delete an access profile grant, detaching the profile from the resource. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Access Profile Source: https://docs.serval.com/api-reference/access-profile-api/get-access-profile /sections/api-reference/openapi-spec-v2.yaml get /v2/access-profiles/{id} Get a specific access profile by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Access Profile Grant Source: https://docs.serval.com/api-reference/access-profile-api/get-access-profile-grant /sections/api-reference/openapi-spec-v2.yaml get /v2/access-profile-grants/{id} Get a specific access profile grant by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Access Profile Grants Source: https://docs.serval.com/api-reference/access-profile-api/list-access-profile-grants /sections/api-reference/openapi-spec-v2.yaml get /v2/access-profile-grants List access profile grants for a team, optionally filtered by access profile, resource type, or resource. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Access Profiles Source: https://docs.serval.com/api-reference/access-profile-api/list-access-profiles /sections/api-reference/openapi-spec-v2.yaml get /v2/access-profiles List all access profiles for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Access Profile Source: https://docs.serval.com/api-reference/access-profile-api/update-access-profile /sections/api-reference/openapi-spec-v2.yaml put /v2/access-profiles/{id} Update an existing access profile. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Access Relationship Source: https://docs.serval.com/api-reference/access-relationship-api/create-access-relationship /sections/api-reference/openapi-spec-v2.yaml post /v2/access-relationships Create an access relationship on a subject (app instance, resource, role, or team). Use relationship_type=OWNER to add an owner. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Integration, Resource, Role:** `apps:write`
**Knowledge item:** `knowledge:write`
**Team:** `teams:manage` | | Team-scoped API key | **Integration, Resource, Role:** `apps:write`
**Knowledge item:** `knowledge:write`
**Team:** Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Access Relationship Source: https://docs.serval.com/api-reference/access-relationship-api/delete-access-relationship /sections/api-reference/openapi-spec-v2.yaml delete /v2/access-relationships/{id} Delete an access relationship. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Integration, Resource, Role:** `apps:write`
**Knowledge item:** `knowledge:write`
**Team:** `teams:manage` | | Team-scoped API key | **Integration, Resource, Role:** `apps:write`
**Knowledge item:** `knowledge:write`
**Team:** Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Access Relationship Source: https://docs.serval.com/api-reference/access-relationship-api/get-access-relationship /sections/api-reference/openapi-spec-v2.yaml get /v2/access-relationships/{id} Get a specific access relationship by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Integration, Resource, Role:** `apps:read`
**Knowledge item:** `knowledge:read`
**Team:** `teams:manage` | | Team-scoped API key | **Integration, Resource, Role:** `apps:read`
**Knowledge item:** `knowledge:read`
**Team:** Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Access Relationships Source: https://docs.serval.com/api-reference/access-relationship-api/list-access-relationships /sections/api-reference/openapi-spec-v2.yaml get /v2/access-relationships List access relationships for a subject (app instance, resource, role, or team). ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Integration, Resource, Role:** `apps:read`
**Knowledge item:** `knowledge:read`
**Team:** `teams:manage` | | Team-scoped API key | **Integration, Resource, Role:** `apps:read`
**Knowledge item:** `knowledge:read`
**Team:** Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Access Relationship Source: https://docs.serval.com/api-reference/access-relationship-api/update-access-relationship /sections/api-reference/openapi-spec-v2.yaml put /v2/access-relationships/{id} Update an access relationship. You can change the relationship type, target, and target type. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Integration, Resource, Role:** `apps:write`
**Knowledge item:** `knowledge:write`
**Team:** `teams:manage` | | Team-scoped API key | **Integration, Resource, Role:** `apps:write`
**Knowledge item:** `knowledge:write`
**Team:** Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Access Request Source: https://docs.serval.com/api-reference/access-request-api/create-access-request /sections/api-reference/openapi-spec-v2.yaml post /v2/access-requests Create an access request for a role. The request will go through the configured approval flow before access is provisioned. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. API-key callers must supply target\_user\_id; otherwise the target defaults to a key ID instead of a user. The role must be requestable and satisfy the access policy. * **Attach to an existing ticket:** With ticket\_id, the ticket must belong to the requested team and be visible to you. # Get Access Request Source: https://docs.serval.com/api-reference/access-request-api/get-access-request /sections/api-reference/openapi-spec-v2.yaml get /v2/access-requests/{id} Get a specific access request by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Access Requests Source: https://docs.serval.com/api-reference/access-request-api/list-access-requests /sections/api-reference/openapi-spec-v2.yaml get /v2/access-requests List access requests for a team. Filter by user, entitlement, app instance, status, or time range. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Requestable Roles Source: https://docs.serval.com/api-reference/access-request-api/list-requestable-roles /sections/api-reference/openapi-spec-v2.yaml get /v2/requestable-roles List roles that are available for requesting access. Returns roles with their access policy IDs so callers can look up policy constraints (max duration, justification requirements) via the Access Policy API. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Revoke Access Request Source: https://docs.serval.com/api-reference/access-request-api/revoke-access-request /sections/api-reference/openapi-spec-v2.yaml post /v2/access-requests/{id}/revoke Revokes an active access request, ending the user's access early. The request must be provisioned and not yet concluded. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Search Access Requests Source: https://docs.serval.com/api-reference/access-request-api/search-access-requests /sections/api-reference/openapi-spec-v2.yaml post /v2/access-requests/search Search access requests with filters. Supports filtering by entitlement, app instance, status, user IDs, time range, and linked ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create App Instance Source: https://docs.serval.com/api-reference/app-instance-api/create-app-instance /sections/api-reference/openapi-spec-v2.yaml post /v2/app-instances Create a new app instance for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete App Instance Source: https://docs.serval.com/api-reference/app-instance-api/delete-app-instance /sections/api-reference/openapi-spec-v2.yaml delete /v2/app-instances/{id} Delete an app instance. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get App Instance Source: https://docs.serval.com/api-reference/app-instance-api/get-app-instance /sections/api-reference/openapi-spec-v2.yaml get /v2/app-instances/{id} Get a specific app instance by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List App Instance Integrations Source: https://docs.serval.com/api-reference/app-instance-api/list-app-instance-integrations /sections/api-reference/openapi-spec-v2.yaml get /v2/app-instances/{app_instance_id}/integrations List integrations for an app instance. Returns integration IDs and metadata (no credentials). Use the integration ID with endpoints like Sync Ticket to Channel. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List App Instances Source: https://docs.serval.com/api-reference/app-instance-api/list-app-instances /sections/api-reference/openapi-spec-v2.yaml get /v2/app-instances List app instances owned by the team along with those shared with it. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update App Instance Source: https://docs.serval.com/api-reference/app-instance-api/update-app-instance /sections/api-reference/openapi-spec-v2.yaml put /v2/app-instances/{id} Update an existing app instance. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Batch Create App Resources Source: https://docs.serval.com/api-reference/app-resource-api/batch-create-app-resources /sections/api-reference/openapi-spec-v2.yaml post /v2/app-resources/batch Create multiple app resources for an app instance in a single request. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Batch Update App Resources Source: https://docs.serval.com/api-reference/app-resource-api/batch-update-app-resources /sections/api-reference/openapi-spec-v2.yaml put /v2/app-resources/batch Update multiple app resources in a single transactional request. Either all updates succeed or all fail. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create App Resource Source: https://docs.serval.com/api-reference/app-resource-api/create-app-resource /sections/api-reference/openapi-spec-v2.yaml post /v2/app-resources Create a new app resource for an app instance. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete App Resource Source: https://docs.serval.com/api-reference/app-resource-api/delete-app-resource /sections/api-reference/openapi-spec-v2.yaml delete /v2/app-resources/{id} Delete an app resource. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get App Resource Source: https://docs.serval.com/api-reference/app-resource-api/get-app-resource /sections/api-reference/openapi-spec-v2.yaml get /v2/app-resources/{id} Get a specific app resource by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List App Resources Source: https://docs.serval.com/api-reference/app-resource-api/list-app-resources /sections/api-reference/openapi-spec-v2.yaml get /v2/app-resources List all app resources for a team, optionally filtered by app instance. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Search App Resources Source: https://docs.serval.com/api-reference/app-resource-api/search-app-resources /sections/api-reference/openapi-spec-v2.yaml post /v2/app-resources/search Search app resources with filters in the request body. Filter by team ID, app instance IDs, or external IDs. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update App Resource Source: https://docs.serval.com/api-reference/app-resource-api/update-app-resource /sections/api-reference/openapi-spec-v2.yaml put /v2/app-resources/{id} Update an existing app resource. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Batch Update App Resource Roles Source: https://docs.serval.com/api-reference/app-resource-role-api/batch-update-app-resource-roles /sections/api-reference/openapi-spec-v2.yaml put /v2/app-resource-roles/batch Update multiple app resource roles in a single transactional request. Either all updates succeed or all fail. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create App Resource Role Source: https://docs.serval.com/api-reference/app-resource-role-api/create-app-resource-role /sections/api-reference/openapi-spec-v2.yaml post /v2/app-resource-roles Create a new app resource role for a resource. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete App Resource Role Source: https://docs.serval.com/api-reference/app-resource-role-api/delete-app-resource-role /sections/api-reference/openapi-spec-v2.yaml delete /v2/app-resource-roles/{id} Delete an app resource role. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get App Resource Role Source: https://docs.serval.com/api-reference/app-resource-role-api/get-app-resource-role /sections/api-reference/openapi-spec-v2.yaml get /v2/app-resource-roles/{id} Get a specific app resource role by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List App Resource Roles Source: https://docs.serval.com/api-reference/app-resource-role-api/list-app-resource-roles /sections/api-reference/openapi-spec-v2.yaml get /v2/app-resource-roles List all app resource roles for a team, optionally filtered by resource. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Search App Resource Roles Source: https://docs.serval.com/api-reference/app-resource-role-api/search-app-resource-roles /sections/api-reference/openapi-spec-v2.yaml post /v2/app-resource-roles/search Search app resource roles by role or parent-resource text, optionally filtered by team, app instance, or resource IDs. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update App Resource Role Source: https://docs.serval.com/api-reference/app-resource-role-api/update-app-resource-role /sections/api-reference/openapi-spec-v2.yaml put /v2/app-resource-roles/{id} Update an existing app resource role. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Approval Delegation Source: https://docs.serval.com/api-reference/approval-delegation-api/create-approval-delegation /sections/api-reference/openapi-spec-v2.yaml post /v2/approval-delegations Create a new approval delegation rule. Optionally specify a delegator_user_id to create on behalf of another user. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Manage a named user’s delegation:** API keys must supply delegator\_user\_id when creating or listing delegations. Omitting it selects the current user. A team-restricted public key cannot authorize against a user. # Delete Approval Delegation Source: https://docs.serval.com/api-reference/approval-delegation-api/delete-approval-delegation /sections/api-reference/openapi-spec-v2.yaml delete /v2/approval-delegations/{id} Delete an approval delegation rule. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Manage a named user’s delegation:** API keys must supply delegator\_user\_id when creating or listing delegations. Omitting it selects the current user. A team-restricted public key cannot authorize against a user. # Get Approval Delegation Source: https://docs.serval.com/api-reference/approval-delegation-api/get-approval-delegation /sections/api-reference/openapi-spec-v2.yaml get /v2/approval-delegations/{id} Get an approval delegation rule by its ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Manage a named user’s delegation:** API keys must supply delegator\_user\_id when creating or listing delegations. Omitting it selects the current user. A team-restricted public key cannot authorize against a user. # List Approval Delegations Source: https://docs.serval.com/api-reference/approval-delegation-api/list-approval-delegations /sections/api-reference/openapi-spec-v2.yaml get /v2/approval-delegations List approval delegation rules. Optionally filter by delegator_user_id. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Manage a named user’s delegation:** API keys must supply delegator\_user\_id when creating or listing delegations. Omitting it selects the current user. A team-restricted public key cannot authorize against a user. # Update Approval Delegation Source: https://docs.serval.com/api-reference/approval-delegation-api/update-approval-delegation /sections/api-reference/openapi-spec-v2.yaml put /v2/approval-delegations/{id} Update an existing approval delegation rule. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Manage a named user’s delegation:** API keys must supply delegator\_user\_id when creating or listing delegations. Omitting it selects the current user. A team-restricted public key cannot authorize against a user. # Get Approval Request Source: https://docs.serval.com/api-reference/approval-request-api/get-approval-request /sections/api-reference/openapi-spec-v2.yaml get /v2/approval-requests/{approval_request_id} Get a single approval request by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Access-request approvals:** `settings:read`
**Workflow-run approvals:** `workflows:read` | | Team-scoped API key | **Access-request approvals:** `settings:read`
**Workflow-run approvals:** `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Approval Request Step Source: https://docs.serval.com/api-reference/approval-request-api/get-approval-request-step /sections/api-reference/openapi-spec-v2.yaml get /v2/approval-requests/{approval_request_id}/steps/{step_id} Get a single step for an approval request. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Access-request approvals:** `settings:read`
**Workflow-run approvals:** `workflows:read` | | Team-scoped API key | **Access-request approvals:** `settings:read`
**Workflow-run approvals:** `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Approval Request Steps Source: https://docs.serval.com/api-reference/approval-request-api/list-approval-request-steps /sections/api-reference/openapi-spec-v2.yaml get /v2/approval-requests/{approval_request_id}/steps List all steps for an approval request, including approver resolutions. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Access-request approvals:** `settings:read`
**Workflow-run approvals:** `workflows:read` | | Team-scoped API key | **Access-request approvals:** `settings:read`
**Workflow-run approvals:** `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Approval Requests Source: https://docs.serval.com/api-reference/approval-request-api/list-approval-requests /sections/api-reference/openapi-spec-v2.yaml get /v2/approval-requests List all approval requests for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Access-request approvals:** `settings:read`
**Workflow-run approvals:** `workflows:read` | | Team-scoped API key | **Access-request approvals:** `settings:read`
**Workflow-run approvals:** `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Search Approval Requests Source: https://docs.serval.com/api-reference/approval-request-api/search-approval-requests /sections/api-reference/openapi-spec-v2.yaml post /v2/approval-requests/search Search approval requests with filters such as resource type, result status, and date range. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Access-request approvals:** `settings:read`
**Workflow-run approvals:** `workflows:read` | | Team-scoped API key | **Access-request approvals:** `settings:read`
**Workflow-run approvals:** `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Audit Logs Source: https://docs.serval.com/api-reference/audit-log-api/list-audit-logs /sections/api-reference/openapi-spec-v2.yaml get /v2/audit-logs List your organization's audit log events from the last 90 days, newest first. To filter by time, set both startTime and endTime; if only one is set, no time filter is applied. Pass nextPageToken from a response as pageToken to get the next page. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `org:audit` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Default request:** Returns events for your own organization only. Users must be organization admins. # Create Token Source: https://docs.serval.com/api-reference/auth-api/create-token /sections/api-reference/auth-openapi-spec.yaml post /v2/auth/token Create a token for use across the API. To obtain your Client ID and Client Secret, visit the [API Settings page](https://app.serval.com/admin/settings) in your Serval dashboard. ## Authentication This endpoint uses HTTP Basic Authentication where: - **Username**: Your Client ID - **Password**: Your Client Secret The Authorization header should contain `Basic `, where the credentials are `client_id:client_secret` encoded in base64. ## Example Request ```bash curl -X POST https://public.api.serval.com/v2/auth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -u "your-client-id:your-client-secret" \ -d "grant_type=client_credentials" ``` Or with explicit Basic auth header: ```bash # First, base64 encode your credentials: client_id:client_secret # For example, if client_id=abc123 and client_secret=secret456 # echo -n "abc123:secret456" | base64 # Result: YWJjMTIzOnNlY3JldDQ1Ng== curl -X POST https://public.api.serval.com/v2/auth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -H "Authorization: Basic YWJjMTIzOnNlY3JldDQ1Ng==" \ -d "grant_type=client_credentials" ``` ## Using the Access Token Once you receive the access token, use it in subsequent API requests: ```bash curl -X GET https://public.api.serval.com/v2/workflows \ -H "Authorization: Bearer your-access-token" ``` ## Scoped keys If your Client ID/Secret pair comes from a scoped API key, the resulting access token is restricted to that key's scopes. This endpoint's request/response shape is unchanged — scoping only affects which requests the token is later authorized to make. ## Authentication and permissions > **Token requirements:** **Organization-scoped API key** or **Team-scoped API key**. > > Send the key's client ID and secret using HTTP Basic to obtain a token. User-based OAuth tokens are not accepted here. | Credential | Access requirements | | - | - | | Organization-scoped API key | Supported; no permission bundle required | | Team-scoped API key | Supported; no permission bundle required | | User-based token (OAuth) | Unsupported | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Exchange public-key credentials:** Use HTTP Basic with client ID and secret and grant\_type=client\_credentials. # Revoke Leaked Key Source: https://docs.serval.com/api-reference/auth-api/revoke-leaked-key /sections/api-reference/auth-openapi-spec.yaml post /v2/auth/revoke Revoke an API key by submitting its secret. Use this when you find a Serval API key secret somewhere it shouldn't be, such as a public repository, a log file, or a chat message. No authentication is required, so anyone who finds a leaked secret can take it out of service immediately. Serval API key secrets start with `svl_secret_` and end in a checksum, so a secret scanner can match them with the pattern `svl_secret_(pk|wk|mk)_[0-9A-Za-z]{49}`. Revoking a key stops it from creating new access tokens and ends the sessions of tokens it already created. Revocation can't be undone. To keep using the API, create a new key from the [API Settings page](https://app.serval.com/admin/settings). ## Example Request ```bash curl -X POST https://public.api.serval.com/v2/auth/revoke \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "secret=svl_secret_pk_..." ``` ## Response The response is `200 OK` with an empty body whether the secret matched a live key, a key that was already revoked, or nothing at all. The endpoint deliberately doesn't reveal whether a secret was valid. ## Authentication and permissions > **Token requirements: No caller token required.** # List Connected Channels Source: https://docs.serval.com/api-reference/connected-channels-api/list-connected-channels /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/connected-channels List existing Slack and Microsoft Teams channel connections, including disabled channels. Direct-message, deleted, and other intake bindings are excluded. Filter by service_instance_id to select an integration instance. Requires channels:read for scoped API keys. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `channels:read` | | Team-scoped API key | `channels:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Set Connected Channel Mode Source: https://docs.serval.com/api-reference/connected-channels-api/set-connected-channel-mode /sections/api-reference/openapi-spec-v2.yaml put /v2/teams/{team_id}/connected-channels/{id}/mode Set the mode of an existing channel connection. Use CONNECTED_SERVICE_MODE_FULL_ASSIST to activate Help desk (Always respond), or CONNECTED_SERVICE_MODE_DISABLED to disable it. The id is the Serval connection UUID, not the platform channel ID. Repeating the current mode is a no-op. Only platform-supported modes are accepted; redirect-to-DM requires a Slack DM surface. Does not create connections or invite the bot. Requires channels:write for scoped API keys. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `channels:write` | | Team-scoped API key | `channels:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Custom Field Option Source: https://docs.serval.com/api-reference/custom-field-api/create-custom-field-option /sections/api-reference/openapi-spec-v2.yaml post /v2/teams/{team_id}/custom-field-options Create a custom field definition on a team's ticket type. Each ticket type has its own field schema, so a field created on REQUEST does not exist on JOURNEY. ENUM and MULTI_SELECT fields require enum_options; every other data type rejects them. Use this before setting values on tickets when the field does not exist yet. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `ticket-fields:write` | | Team-scoped API key | `ticket-fields:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Custom Field Options Source: https://docs.serval.com/api-reference/custom-field-api/list-custom-field-options /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/custom-field-options List the available custom field definitions for a team and ticket type. Returns field definitions with empty values. Use this to discover field keys before setting values on tickets. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Custom Role Source: https://docs.serval.com/api-reference/custom-role-api/create-custom-role /sections/api-reference/openapi-spec-v2.yaml post /v2/teams/{team_id}/custom-roles Create a custom role on a team. A custom role extends a built-in base role with additional grantable actions. Assign it to a group with the Team Group API's custom_role_id. Requires custom roles to be enabled for the organization. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Default request:** With a user OAuth token, you also need Edit Team Settings on the role's team, and you can grant only actions you already hold there. # Delete Custom Role Source: https://docs.serval.com/api-reference/custom-role-api/delete-custom-role /sections/api-reference/openapi-spec-v2.yaml delete /v2/custom-roles/{id} Delete a custom role. Users and groups holding it keep their membership on the team with the role's base role as a plain built-in role. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Default request:** With a user OAuth token, you also need Edit Team Settings on the role's team, and you can grant only actions you already hold there. # Get Custom Role Source: https://docs.serval.com/api-reference/custom-role-api/get-custom-role /sections/api-reference/openapi-spec-v2.yaml get /v2/custom-roles/{id} Get a custom role, including the actions it grants on top of its base role. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Custom Roles Source: https://docs.serval.com/api-reference/custom-role-api/list-custom-roles /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/custom-roles List a team's custom roles. team_id is required. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Custom Role Source: https://docs.serval.com/api-reference/custom-role-api/update-custom-role /sections/api-reference/openapi-spec-v2.yaml put /v2/custom-roles/{id} Update a custom role's name, description, base role, and granted actions. granted_actions replaces the full set. Changing the base role re-pins every member of the role to the new base. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Default request:** With a user OAuth token, you also need Edit Team Settings on the role's team, and you can grant only actions you already hold there. # Create Custom Service Source: https://docs.serval.com/api-reference/custom-service-api/create-custom-service /sections/api-reference/openapi-spec-v2.yaml post /v2/custom-services Create a new custom service for a team. Custom services represent external APIs or systems that are not built-in integrations. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Custom Service Source: https://docs.serval.com/api-reference/custom-service-api/delete-custom-service /sections/api-reference/openapi-spec-v2.yaml delete /v2/custom-services/{id} Delete a custom service. This will not delete any app instances that use this custom service. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Custom Service Source: https://docs.serval.com/api-reference/custom-service-api/get-custom-service /sections/api-reference/openapi-spec-v2.yaml get /v2/custom-services/{id} Get a specific custom service by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Custom Services Source: https://docs.serval.com/api-reference/custom-service-api/list-custom-services /sections/api-reference/openapi-spec-v2.yaml get /v2/custom-services List all custom services for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Custom Service Source: https://docs.serval.com/api-reference/custom-service-api/update-custom-service /sections/api-reference/openapi-spec-v2.yaml put /v2/custom-services/{id} Update an existing custom service. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Email Intake Configs Source: https://docs.serval.com/api-reference/email-intake-api/list-email-intake-configs /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/email-intake-configs List the email addresses a team receives tickets through. Each config's id is the referent an assignment-rule intake condition points at (encoded "email:"); connected Slack and Microsoft Teams channels are the other intake id-space. Requires email-intake:read for scoped API keys. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `email-intake:read` | | Team-scoped API key | `email-intake:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Aggregate Entities Source: https://docs.serval.com/api-reference/entity-api/aggregate-entities /sections/api-reference/openapi-spec-v2.yaml post /v2/entities/aggregate Aggregate live-entity counts for one entity schema (database), grouped by entity type or by creation-time bucket (day or month). Supports optional entity-type restriction and an optional created-at window. This is the scalable way to count entities — counting via paginated search does not scale to large databases. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Read team entities:** Schema and row-access rules still apply. # Archive Entity Source: https://docs.serval.com/api-reference/entity-api/archive-entity /sections/api-reference/openapi-spec-v2.yaml post /v2/entities/{id}/archive Archive an entity, hiding it from active browse while keeping its key reserved so the key cannot be reused. Reversible via Unarchive. Distinct from Delete, which is permanent and frees the key. Archived entities are excluded from Search Entities unless include_archived is set. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Write team entities:** Schema and row-access rules still apply. # Create Entity Source: https://docs.serval.com/api-reference/entity-api/create-entity /sections/api-reference/openapi-spec-v2.yaml post /v2/entities Create a new entity for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Write team entities:** Schema and row-access rules still apply. # Delete Entity Source: https://docs.serval.com/api-reference/entity-api/delete-entity /sections/api-reference/openapi-spec-v2.yaml delete /v2/entities/{id} Delete an entity. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Entity Source: https://docs.serval.com/api-reference/entity-api/get-entity /sections/api-reference/openapi-spec-v2.yaml get /v2/entities/{id} Get a specific entity by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Read team entities:** Schema and row-access rules still apply. # List Entities Source: https://docs.serval.com/api-reference/entity-api/list-entities /sections/api-reference/openapi-spec-v2.yaml get /v2/entities List entities for a team. Optionally filter by entity type. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Read team entities:** Schema and row-access rules still apply. # List Entity Field Value History Source: https://docs.serval.com/api-reference/entity-api/list-entity-field-value-history /sections/api-reference/openapi-spec-v2.yaml get /v2/entities/{entity_id}/field-history List the change history for an entity's field values. Returns historical and current values ordered by most recent first. Optionally filter by field ID or field key. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Read team entities:** Schema and row-access rules still apply. # Reveal Sensitive Entity Field Value Source: https://docs.serval.com/api-reference/entity-api/reveal-sensitive-entity-field-value /sections/api-reference/openapi-spec-v2.yaml post /v2/entities/{entity_id}/reveal-field Reveal the value of a sensitive field on one entity. Entity reads withhold values of fields marked sensitive and return the field with `sensitive: true` and no value. Call this only after a read returned such a field, passing that entry's field_id or field_key. Every call is recorded in the audit log. Set include_history to also receive the field's value history. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Read team entities:** Schema and row-access rules still apply. # Search Entities Source: https://docs.serval.com/api-reference/entity-api/search-entities /sections/api-reference/openapi-spec-v2.yaml post /v2/entities/search Search entities with advanced filtering, sorting, and pagination. Supports filtering by entity type, name search, field filters (with OR between filter groups and AND within groups), and custom sorting. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Read team entities:** Schema and row-access rules still apply. # Unarchive Entity Source: https://docs.serval.com/api-reference/entity-api/unarchive-entity /sections/api-reference/openapi-spec-v2.yaml post /v2/entities/{id}/unarchive Restore an archived entity to active browse. The key was reserved throughout, so this can never collide. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Write team entities:** Schema and row-access rules still apply. # Update Entity Source: https://docs.serval.com/api-reference/entity-api/update-entity /sections/api-reference/openapi-spec-v2.yaml put /v2/entities/{id} Update an existing entity. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Write team entities:** Schema and row-access rules still apply. # Create Entity Field Mapping Source: https://docs.serval.com/api-reference/entity-field-mapping-api/create-entity-field-mapping /sections/api-reference/openapi-spec-v2.yaml post /v2/entity-field-mappings Create a field mapping binding an external source field (from an ingestion config's discovered external schema) to an internal entity-type field. Already-ingested records are republished with the new mapping immediately; no sync is needed. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Entity Field Mapping Source: https://docs.serval.com/api-reference/entity-field-mapping-api/delete-entity-field-mapping /sections/api-reference/openapi-spec-v2.yaml delete /v2/entity-field-mappings/{id} Delete a field mapping. Already-ingested records are republished without it immediately; no sync is needed. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Entity Field Mapping Source: https://docs.serval.com/api-reference/entity-field-mapping-api/get-entity-field-mapping /sections/api-reference/openapi-spec-v2.yaml get /v2/entity-field-mappings/{id} Get a field mapping by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get External Entity Schema Source: https://docs.serval.com/api-reference/entity-field-mapping-api/get-external-entity-schema /sections/api-reference/openapi-spec-v2.yaml get /v2/entity-ingestion-configs/{ingestion_config_id}/external-schema Get the external schema discovered from the most recent sync of an ingestion config. Its json_schema lists the external field paths available to map into entity-type fields. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Entity Field Mappings Source: https://docs.serval.com/api-reference/entity-field-mapping-api/list-entity-field-mappings /sections/api-reference/openapi-spec-v2.yaml get /v2/entity-field-mappings List the field mappings for an entity type, optionally narrowed to a single ingestion config's source. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Entity Field Mapping Source: https://docs.serval.com/api-reference/entity-field-mapping-api/update-entity-field-mapping /sections/api-reference/openapi-spec-v2.yaml put /v2/entity-field-mappings/{id} Update a field mapping's external field path and/or precedence. Omitted fields are left unchanged. Already-ingested records are republished with the updated mapping immediately; no sync is needed. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Entity Ingestion Config Source: https://docs.serval.com/api-reference/entity-ingestion-config-api/create-entity-ingestion-config /sections/api-reference/openapi-spec-v2.yaml post /v2/entity-ingestion-configs Create an entity ingestion config that links a workflow to an entity type for periodic data synchronization. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Entity Ingestion Config Source: https://docs.serval.com/api-reference/entity-ingestion-config-api/delete-entity-ingestion-config /sections/api-reference/openapi-spec-v2.yaml delete /v2/entity-ingestion-configs/{config_id} Delete an entity ingestion config. Optionally delete all ingested entities and field values (asynchronous operation). ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Entity Ingestion Config Source: https://docs.serval.com/api-reference/entity-ingestion-config-api/get-entity-ingestion-config /sections/api-reference/openapi-spec-v2.yaml get /v2/entity-ingestion-configs/{config_id} Get a specific entity ingestion config by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Ingestion Config Sync Status Source: https://docs.serval.com/api-reference/entity-ingestion-config-api/get-ingestion-config-sync-status /sections/api-reference/openapi-spec-v2.yaml get /v2/entity-ingestion-configs/{config_id}/sync-status Get the sync status for an entity ingestion config, including last sync time, current phase, and data availability flags. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Entity Ingestion Runs Source: https://docs.serval.com/api-reference/entity-ingestion-config-api/list-entity-ingestion-runs /sections/api-reference/openapi-spec-v2.yaml get /v2/entity-ingestion-configs/{ingestion_config_id}/runs List the ingestion runs for an entity ingestion config, most-recent-first, including status, per-item counts, and any failure. Use to verify that ingested data landed. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Ingestion Configs Source: https://docs.serval.com/api-reference/entity-ingestion-config-api/list-ingestion-configs /sections/api-reference/openapi-spec-v2.yaml get /v2/entity-ingestion-configs List entity ingestion configs for a team, optionally filtered by app instance. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Sync Entity Ingestion Config Source: https://docs.serval.com/api-reference/entity-ingestion-config-api/sync-entity-ingestion-config /sections/api-reference/openapi-spec-v2.yaml post /v2/entity-ingestion-configs/{config_id}/sync Trigger a sync for an entity ingestion config. Starts the ingestion workflow to fetch and sync external data. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Entity Ingestion Config Source: https://docs.serval.com/api-reference/entity-ingestion-config-api/update-entity-ingestion-config /sections/api-reference/openapi-spec-v2.yaml patch /v2/entity-ingestion-configs/{config_id} Update an entity ingestion config. Supports partial updates — only provided fields are changed. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Cancel Schema Migration Source: https://docs.serval.com/api-reference/entity-type-api/cancel-schema-migration /sections/api-reference/openapi-spec-v2.yaml post /v2/schema-migrations/{id}/cancel Cancel a still-pending schema migration. Once the worker has started applying it, the request fails with FailedPrecondition. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Entity Type Source: https://docs.serval.com/api-reference/entity-type-api/create-entity-type /sections/api-reference/openapi-spec-v2.yaml post /v2/entity-types Create a new entity type with optional fields for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Entity Type Field Source: https://docs.serval.com/api-reference/entity-type-api/create-entity-type-field /sections/api-reference/openapi-spec-v2.yaml post /v2/entity-type-fields Create a field on an entity type. Returns the schema_migration_id of the (already-completed) create migration; fetch it via Get Schema Migration to read the new field id from details.create_field.field_id. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Entity Type Source: https://docs.serval.com/api-reference/entity-type-api/delete-entity-type /sections/api-reference/openapi-spec-v2.yaml delete /v2/entity-types/{id} Delete an entity type. WARNING: this cascade-deletes the type and all of its descendant types; entity records of these types are orphaned (hidden), not deleted. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Entity Type Field Source: https://docs.serval.com/api-reference/entity-type-api/delete-entity-type-field /sections/api-reference/openapi-spec-v2.yaml delete /v2/entity-type-fields/{id} Delete an entity type field. By default the field is also removed from descendant types that inherit it; set keep_on_children=true to detach instead. This is an asynchronous schema migration: the response contains schema_migration_id, which you poll via Get Schema Migration to track completion. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Entity Type Source: https://docs.serval.com/api-reference/entity-type-api/get-entity-type /sections/api-reference/openapi-spec-v2.yaml get /v2/entity-types/{id} Get an entity type by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Entity Type Field Source: https://docs.serval.com/api-reference/entity-type-api/get-entity-type-field /sections/api-reference/openapi-spec-v2.yaml get /v2/entity-type-fields/{id} Get an entity type field by ID, including its enum options. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Schema Migration Source: https://docs.serval.com/api-reference/entity-type-api/get-schema-migration /sections/api-reference/openapi-spec-v2.yaml get /v2/schema-migrations/{id} Get a schema migration by ID, including its current status (PENDING, IN_PROGRESS, APPLIED, COMPLETED, FAILED, or CANCELLED). ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Entity Types Source: https://docs.serval.com/api-reference/entity-type-api/list-entity-types /sections/api-reference/openapi-spec-v2.yaml get /v2/entity-types List all entity types for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Schema Migrations Source: https://docs.serval.com/api-reference/entity-type-api/list-schema-migrations /sections/api-reference/openapi-spec-v2.yaml get /v2/entity-types/{entity_type_id}/schema-migrations List the schema migration history for an entity type, newest first. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Search Entity Types Source: https://docs.serval.com/api-reference/entity-type-api/search-entity-types /sections/api-reference/openapi-spec-v2.yaml post /v2/entity-types/search Search for entity types by key or other filters. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:read` | | Team-scoped API key | `entities:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Entity Type Source: https://docs.serval.com/api-reference/entity-type-api/update-entity-type /sections/api-reference/openapi-spec-v2.yaml put /v2/entity-types/{id} Update an entity type's name, color, icon, or help-agent visibility. Omitted optional fields are left unchanged. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Entity Type Field Source: https://docs.serval.com/api-reference/entity-type-api/update-entity-type-field /sections/api-reference/openapi-spec-v2.yaml put /v2/entity-type-fields/{id} Update an entity type field: rename it (set name) and/or change its data type (set data_type, plus enum_options when the new type is ENUM/MULTI_SELECT). At most one attribute may change per request. This is an asynchronous schema migration: the response contains schema_migration_id, which you poll via Get Schema Migration to track completion. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `entities:write` | | Team-scoped API key | `entities:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Folder Source: https://docs.serval.com/api-reference/folder-api/create-folder /sections/api-reference/openapi-spec-v2.yaml post /v2/folders Create a folder to organize folder items. Set item_type to choose the item type; pass parent_folder_id to nest under an existing folder of the same type. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Workflow folder:** `workflows:write`
**Skill folder:** `skills:write`
**Form folder:** `settings:write` | | Team-scoped API key | **Workflow folder:** `workflows:write`
**Skill folder:** `skills:write`
**Form folder:** `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Folder Source: https://docs.serval.com/api-reference/folder-api/delete-folder /sections/api-reference/openapi-spec-v2.yaml delete /v2/folders/{id} Delete a folder. The folder is soft-deleted; any items or sub-folders it contained are moved to the root rather than deleted. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Workflow folder:** `workflows:write`
**Skill folder:** `skills:write`
**Form folder:** `settings:write` | | Team-scoped API key | **Workflow folder:** `workflows:write`
**Skill folder:** `skills:write`
**Form folder:** `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Folder Source: https://docs.serval.com/api-reference/folder-api/get-folder /sections/api-reference/openapi-spec-v2.yaml get /v2/folders/{id} Get a single folder by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Workflow folder:** `workflows:read`
**Skill folder:** `skills:read`
**Form folder:** `settings:read` | | Team-scoped API key | **Workflow folder:** `workflows:read`
**Skill folder:** `skills:read`
**Form folder:** `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Folder Contents Source: https://docs.serval.com/api-reference/folder-api/list-folder-contents /sections/api-reference/openapi-spec-v2.yaml get /v2/folder-contents List the direct items in a folder. Leave folder_id unset to list the root. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Workflow folder:** `workflows:read`
**Skill folder:** `skills:read`
**Form folder:** `settings:read` | | Team-scoped API key | **Workflow folder:** `workflows:read`
**Skill folder:** `skills:read`
**Form folder:** `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Folders Source: https://docs.serval.com/api-reference/folder-api/list-folders /sections/api-reference/openapi-spec-v2.yaml get /v2/folders List a team's folders of a given item_type as a flat list (use parent_folder_id to reconstruct the tree). ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Workflow folder:** `workflows:read`
**Skill folder:** `skills:read`
**Form folder:** `settings:read` | | Team-scoped API key | **Workflow folder:** `workflows:read`
**Skill folder:** `skills:read`
**Form folder:** `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Set Folder Item Location Source: https://docs.serval.com/api-reference/folder-api/set-folder-item-location /sections/api-reference/openapi-spec-v2.yaml put /v2/folder-item-locations Set the folder location for a folder item, or move it to the root by leaving folder_id unset. The destination must be in the same team and compatible folder tree as the item. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Workflow folder:** `workflows:write`
**Skill folder:** `skills:write`
**Form folder:** `settings:write` | | Team-scoped API key | **Workflow folder:** `workflows:write`
**Skill folder:** `skills:write`
**Form folder:** `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Folder Source: https://docs.serval.com/api-reference/folder-api/update-folder /sections/api-reference/openapi-spec-v2.yaml put /v2/folders/{id} Rename and/or move a folder. Include the parent field to move the folder (set parent_folder_id to move under another folder, or leave it unset to move to the root). ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Workflow folder:** `workflows:write`
**Skill folder:** `skills:write`
**Form folder:** `settings:write` | | Team-scoped API key | **Workflow folder:** `workflows:write`
**Skill folder:** `skills:write`
**Form folder:** `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Form Source: https://docs.serval.com/api-reference/forms-api/create-form /sections/api-reference/openapi-spec-v2.yaml post /v2/forms Create a form for a team from module source (TSX importing "serval/forms"). The form lands as an unpublished draft unless is_published is set, in which case the module is compiled and every workflow it imports must already be published on the team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Form Source: https://docs.serval.com/api-reference/forms-api/delete-form /sections/api-reference/openapi-spec-v2.yaml delete /v2/forms/{id} Delete a form. Sessions already opened against it are unaffected. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Form Source: https://docs.serval.com/api-reference/forms-api/get-form /sections/api-reference/openapi-spec-v2.yaml get /v2/forms/{id} Get a specific form by ID, including the module source of the version currently shown in the builder (the latest draft, or the published version when there is no newer draft). ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Forms Source: https://docs.serval.com/api-reference/forms-api/list-forms /sections/api-reference/openapi-spec-v2.yaml get /v2/forms List a team's forms. Pass is_published=false to list only the forms that have never been published — the drafts experimentation leaves behind — then delete them individually. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Form Source: https://docs.serval.com/api-reference/forms-api/update-form /sections/api-reference/openapi-spec-v2.yaml put /v2/forms/{id} Update a form's draft. Omitted (or empty) name, description, and content are left unchanged. Set is_published to true to publish the resulting draft, or is_enabled to false to stop the form accepting new sessions without deleting it. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Group Source: https://docs.serval.com/api-reference/group-api/create-group /sections/api-reference/openapi-spec-v2.yaml post /v2/groups Create a new group. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Create an organization-wide group:** `groups:manage`
**Create a team-owned group, Create a team-owned group as organization admin:** Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Create an organization-wide group:** Omit manager\_team\_id. * **Create a team-owned group:** Supply manager\_team\_id. * **Create a team-owned group as organization admin:** The organization fallback requires a user identity; an organization API key cannot use it. # Delete Group Source: https://docs.serval.com/api-reference/group-api/delete-group /sections/api-reference/openapi-spec-v2.yaml delete /v2/groups/{id} Delete a group. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Manage an organization-wide group:** `groups:manage`
**Manage a restricted group:** Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Manage a restricted group:** A second check requires a user owner, an organization-admin user, or permission to manage groups on a manager team. Public API keys cannot manage restricted groups. # Get Group Source: https://docs.serval.com/api-reference/group-api/get-group /sections/api-reference/openapi-spec-v2.yaml get /v2/groups/{id} Get a specific group by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `groups:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Read groups:** Group visibility rules still apply. A team filter does not change the organization authorization check. # List Groups Source: https://docs.serval.com/api-reference/group-api/list-groups /sections/api-reference/openapi-spec-v2.yaml get /v2/groups List groups. Filter by user_id to get every group a user belongs to. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `groups:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Read groups:** Group visibility rules still apply. A team filter does not change the organization authorization check. # Update Group Source: https://docs.serval.com/api-reference/group-api/update-group /sections/api-reference/openapi-spec-v2.yaml put /v2/groups/{id} Update an existing group. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Manage an organization-wide group:** `groups:manage`
**Manage a restricted group:** Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Manage a restricted group:** A second check requires a user owner, an organization-admin user, or permission to manage groups on a manager team. Public API keys cannot manage restricted groups. # Create Guidance Source: https://docs.serval.com/api-reference/guidance-api/create-guidance /sections/api-reference/openapi-spec-v2.yaml post /v2/guidances Create a new guidance for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `skills:write` | | Team-scoped API key | `skills:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Guidance Source: https://docs.serval.com/api-reference/guidance-api/delete-guidance /sections/api-reference/openapi-spec-v2.yaml delete /v2/guidances/{id} Delete a guidance. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `skills:write` | | Team-scoped API key | `skills:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Guidance Source: https://docs.serval.com/api-reference/guidance-api/get-guidance /sections/api-reference/openapi-spec-v2.yaml get /v2/guidances/{id} Get a specific guidance by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `skills:read` | | Team-scoped API key | `skills:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Guidance Versions Source: https://docs.serval.com/api-reference/guidance-api/list-guidance-versions /sections/api-reference/openapi-spec-v2.yaml get /v2/guidances/{guidance_id}/versions List the version history of a guidance (Help Desk Skill). By default returns only published versions (newest first). Each version carries its own id, name, description, content, author, and publish timestamp — use this to answer what changed in a skill and when. Pass include_unpublished_drafts=true to also include unpublished drafts. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `skills:read` | | Team-scoped API key | `skills:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Guidances Source: https://docs.serval.com/api-reference/guidance-api/list-guidances /sections/api-reference/openapi-spec-v2.yaml get /v2/guidances List all guidances for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `skills:read` | | Team-scoped API key | `skills:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Guidance Source: https://docs.serval.com/api-reference/guidance-api/update-guidance /sections/api-reference/openapi-spec-v2.yaml put /v2/guidances/{id} Update an existing guidance. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `skills:write` | | Team-scoped API key | `skills:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Journey Source: https://docs.serval.com/api-reference/journey-api/get-journey /sections/api-reference/openapi-spec-v2.yaml get /v2/journeys/{id} Fetch a single journey snapshot with tasks, health checks, and workflow failures. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Journeys Source: https://docs.serval.com/api-reference/journey-api/list-journeys /sections/api-reference/openapi-spec-v2.yaml post /v2/teams/{team_id}/journeys/search List lean journey rows for a team, optionally filtered and sorted. Returns identity, requester, progress, and health check counts per journey; call GetJourney for tasks and workflow failures. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create One-Time Window Source: https://docs.serval.com/api-reference/one-time-window-api/create-one-time-window /sections/api-reference/openapi-spec-v2.yaml post /v2/teams/{team_id}/one-time-windows Create a single team-scoped HOLIDAY, BLACKOUT, or informational window. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `schedules:write` | | Team-scoped API key | `schedules:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete One-Time Window Source: https://docs.serval.com/api-reference/one-time-window-api/delete-one-time-window /sections/api-reference/openapi-spec-v2.yaml delete /v2/one-time-windows/{id} Delete a one-time window. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `schedules:write` | | Team-scoped API key | `schedules:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get One-Time Window Source: https://docs.serval.com/api-reference/one-time-window-api/get-one-time-window /sections/api-reference/openapi-spec-v2.yaml get /v2/one-time-windows/{id} Retrieve a one-time window by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `schedules:read` | | Team-scoped API key | `schedules:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List One-Time Windows Source: https://docs.serval.com/api-reference/one-time-window-api/list-one-time-windows /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/one-time-windows List a team's one-time windows. Filter by kind to select HOLIDAY, BLACKOUT, or OTHER windows. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `schedules:read` | | Team-scoped API key | `schedules:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **All schedule kinds:** An unfiltered list requires both permissions. # Update One-Time Window Source: https://docs.serval.com/api-reference/one-time-window-api/update-one-time-window /sections/api-reference/openapi-spec-v2.yaml patch /v2/one-time-windows/{id} Update a one-time window. Its kind and owning team are immutable. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `schedules:write` | | Team-scoped API key | `schedules:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Batch Get Review Items Source: https://docs.serval.com/api-reference/review-api/batch-get-review-items /sections/api-reference/openapi-spec-v2.yaml post /v2/reviews/{review_id}/items:batchGet Read before and after documents for 1–20 unique item IDs from one review, in request order. Uses the same comparison and secret scrubbing as GetReviewItem. Missing or foreign items fail the entire request; unsupported content is reported per item. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **API key:** `reviews:read`
**User: session review, User: promotion, User: parent-to-branch pull:** Unsupported | | Team-scoped API key | **API key:** `reviews:read`
**User: session review, User: promotion, User: parent-to-branch pull:** Unsupported | | User-based token (OAuth) | **API key:** Unsupported
**User: session review, User: promotion, User: parent-to-branch pull:** Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **API key:** The key must allow the session's team, or either the source or target team of a promotion. The review's target team must belong to your organization. * **User: session review:** Requires permission to view configuration sessions in the session's team. * **User: promotion:** Requires review permission on the target team, or both staging permission on the target team and author permission on the source team. Cross-organization access from the source team requires an active team link between organizations in the same Parent Organization. * **User: parent-to-branch pull:** For a recorded parent-to-branch pull, staging permission on the target branch and branch permission on the source parent also authorize access. # Get Review Source: https://docs.serval.com/api-reference/review-api/get-review /sections/api-reference/openapi-spec-v2.yaml get /v2/reviews/{review_id} Read a review's source, apply state, and current approval requirement. Approval status does not imply that changes have been applied. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **API key:** `reviews:read`
**User: session review, User: promotion, User: parent-to-branch pull:** Unsupported | | Team-scoped API key | **API key:** `reviews:read`
**User: session review, User: promotion, User: parent-to-branch pull:** Unsupported | | User-based token (OAuth) | **API key:** Unsupported
**User: session review, User: promotion, User: parent-to-branch pull:** Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **API key:** The key must allow the session's team, or either the source or target team of a promotion. The review's target team must belong to your organization. * **User: session review:** Requires permission to view configuration sessions in the session's team. * **User: promotion:** Requires review permission on the target team, or both staging permission on the target team and author permission on the source team. Cross-organization access from the source team requires an active team link between organizations in the same Parent Organization. * **User: parent-to-branch pull:** For a recorded parent-to-branch pull, staging permission on the target branch and branch permission on the source parent also authorize access. # Get Review Item Source: https://docs.serval.com/api-reference/review-api/get-review-item /sections/api-reference/openapi-spec-v2.yaml get /v2/reviews/{review_id}/items/{item_id} Read secret-scrubbed before and after documents using the review UI's comparison baseline. Pending changes may use live resource state. Missing_base or unsupported means the item cannot be fully reviewed; never treat missing content as approval. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **API key:** `reviews:read`
**User: session review, User: promotion, User: parent-to-branch pull:** Unsupported | | Team-scoped API key | **API key:** `reviews:read`
**User: session review, User: promotion, User: parent-to-branch pull:** Unsupported | | User-based token (OAuth) | **API key:** Unsupported
**User: session review, User: promotion, User: parent-to-branch pull:** Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **API key:** The key must allow the session's team, or either the source or target team of a promotion. The review's target team must belong to your organization. * **User: session review:** Requires permission to view configuration sessions in the session's team. * **User: promotion:** Requires review permission on the target team, or both staging permission on the target team and author permission on the source team. Cross-organization access from the source team requires an active team link between organizations in the same Parent Organization. * **User: parent-to-branch pull:** For a recorded parent-to-branch pull, staging permission on the target branch and branch permission on the source parent also authorize access. # List Review Items Source: https://docs.serval.com/api-reference/review-api/list-review-items /sections/api-reference/openapi-spec-v2.yaml get /v2/reviews/{review_id}/items List review item metadata using page_size and page_token. Fetch documents with GetReviewItem or BatchGetReviewItems. Follow nextPageToken until empty. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **API key:** `reviews:read`
**User: session review, User: promotion, User: parent-to-branch pull:** Unsupported | | Team-scoped API key | **API key:** `reviews:read`
**User: session review, User: promotion, User: parent-to-branch pull:** Unsupported | | User-based token (OAuth) | **API key:** Unsupported
**User: session review, User: promotion, User: parent-to-branch pull:** Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **API key:** The key must allow the session's team, or either the source or target team of a promotion. The review's target team must belong to your organization. * **User: session review:** Requires permission to view configuration sessions in the session's team. * **User: promotion:** Requires review permission on the target team, or both staging permission on the target team and author permission on the source team. Cross-organization access from the source team requires an active team link between organizations in the same Parent Organization. * **User: parent-to-branch pull:** For a recorded parent-to-branch pull, staging permission on the target branch and branch permission on the source parent also authorize access. # List Reviews Source: https://docs.serval.com/api-reference/review-api/list-reviews /sections/api-reference/openapi-spec-v2.yaml get /v2/reviews List a team's session reviews and incoming promotions, or use outgoing=true for promotions from that team. Results use cursor pagination. Each subsequent review or item request checks access independently. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **API key:** `reviews:read`
**User: session reviews and incoming promotions, User: outgoing promotions:** Unsupported | | Team-scoped API key | **API key:** `reviews:read`
**User: session reviews and incoming promotions, User: outgoing promotions:** Unsupported | | User-based token (OAuth) | **API key:** Unsupported
**User: session reviews and incoming promotions, User: outgoing promotions:** Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **API key:** The requested team must be in your organization and allowed by the key. Use outgoing=true for promotions from that team. * **User: session reviews and incoming promotions:** Requires permission to view configuration sessions in the requested team. * **User: outgoing promotions:** With outgoing=true, requires permission to author promotions from the requested team. # Create Reclamation Candidate Source: https://docs.serval.com/api-reference/roles-api/create-reclamation-candidate /sections/api-reference/openapi-spec-v2.yaml post /v2/teams/{team_id}/reclamation-candidates Flag an entitlement grant for reclamation now, on your own logic, without waiting for the inactivity sweep. If a reclamation policy is attached to the entitlement it opens a gated review; otherwise the access is reclaimed automatically. Returns the created reclamation. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Dismiss Reclamation Candidate Source: https://docs.serval.com/api-reference/roles-api/dismiss-reclamation-candidate /sections/api-reference/openapi-spec-v2.yaml post /v2/teams/{team_id}/reclamation-candidates/{id}/dismiss Dismiss an in-review reclamation candidate: conclude its review as dismissed, leaving the grant in place. A manage-level action — the caller need not be an assigned reviewer. Returns the updated reclamation. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Reclamation Candidates Source: https://docs.serval.com/api-reference/roles-api/list-reclamation-candidates /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/reclamation-candidates List a team's reclamation-candidate reclamations — entitlement grants flagged for review or reclaim because the user stopped signing in. Filter by status, app instance, or a name search. The response also carries the team-wide reclaimed/dismissed tally shown on the roles page. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:read` | | Team-scoped API key | `apps:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Reclaim Reclamation Candidate Source: https://docs.serval.com/api-reference/roles-api/reclaim-reclamation-candidate /sections/api-reference/openapi-spec-v2.yaml post /v2/teams/{team_id}/reclamation-candidates/{id}/reclaim Reclaim an in-review reclamation candidate: conclude its review as reclaimed and start deprovisioning the grant. A manage-level action — the caller need not be an assigned reviewer. Returns the updated reclamation. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `apps:write` | | Team-scoped API key | `apps:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Schedule Source: https://docs.serval.com/api-reference/schedule-api/create-schedule /sections/api-reference/openapi-spec-v2.yaml post /v2/teams/{team_id}/schedules Create a recurring schedule for a team. WORK_HOURS schedules drive SLA clocks; BLACKOUT schedules define recurring change freezes. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `schedules:write` | | Team-scoped API key | `schedules:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Schedule Source: https://docs.serval.com/api-reference/schedule-api/delete-schedule /sections/api-reference/openapi-spec-v2.yaml delete /v2/schedules/{id} Delete a recurring schedule. Schedules referenced by active configuration cannot be deleted. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `schedules:write` | | Team-scoped API key | `schedules:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Schedule Source: https://docs.serval.com/api-reference/schedule-api/get-schedule /sections/api-reference/openapi-spec-v2.yaml get /v2/schedules/{id} Retrieve a recurring schedule by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `schedules:read` | | Team-scoped API key | `schedules:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Schedules Source: https://docs.serval.com/api-reference/schedule-api/list-schedules /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/schedules List a team's recurring schedules. Filter by kind to select WORK_HOURS or BLACKOUT schedules. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `schedules:read` | | Team-scoped API key | `schedules:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **All schedule kinds:** An unfiltered list requires both permissions. # Update Schedule Source: https://docs.serval.com/api-reference/schedule-api/update-schedule /sections/api-reference/openapi-spec-v2.yaml patch /v2/schedules/{id} Update a recurring schedule. Omitted fields are preserved; an empty respected_holiday_window_ids update clears every holiday reference. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `schedules:write` | | Team-scoped API key | `schedules:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create SLA Definition Source: https://docs.serval.com/api-reference/sla-api/create-sla-definition /sections/api-reference/openapi-spec-v2.yaml post /v2/teams/{team_id}/sla-definitions Create an SLA definition for a team. SLA definitions specify target resolution times, business hours schedules, and auto-attachment criteria. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete SLA Definition Source: https://docs.serval.com/api-reference/sla-api/delete-sla-definition /sections/api-reference/openapi-spec-v2.yaml delete /v2/sla-definitions/{id} Delete an SLA definition. Fails if the definition is referenced by active task SLAs. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get SLA Definition Source: https://docs.serval.com/api-reference/sla-api/get-sla-definition /sections/api-reference/openapi-spec-v2.yaml get /v2/sla-definitions/{id} Retrieve a single SLA definition by ID, including its conditions, attachment criteria, and action definitions. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List SLA Definitions Source: https://docs.serval.com/api-reference/sla-api/list-sla-definitions /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/sla-definitions List all SLA definitions for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update SLA Definition Source: https://docs.serval.com/api-reference/sla-api/update-sla-definition /sections/api-reference/openapi-spec-v2.yaml patch /v2/sla-definitions/{id} Update an SLA definition. All fields are optional; only provided fields are updated. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Add Tag To Subject Source: https://docs.serval.com/api-reference/tag-api/add-tag-to-subject /sections/api-reference/openapi-spec-v2.yaml post /v2/tags/add-to-subject Attach a tag to a subject (resource, role, app instance, workflow, or guidance). ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Resource tags, Role tags, Integration tags:** `apps:write`
**Form tags, Form Block tags:** `settings:write`
**Workflow tags:** `workflows:write`
**Skill tags:** `skills:write` | | Team-scoped API key | **Resource tags, Role tags, Integration tags:** `apps:write`
**Form tags, Form Block tags:** `settings:write`
**Workflow tags:** `workflows:write`
**Skill tags:** `skills:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. Authorization follows the tagged subject. Granting permission to edit tag definitions alone does not authorize editing every tagged resource. # Create Tag Source: https://docs.serval.com/api-reference/tag-api/create-tag /sections/api-reference/openapi-spec-v2.yaml post /v2/tags Create a new tag. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Tag Source: https://docs.serval.com/api-reference/tag-api/delete-tag /sections/api-reference/openapi-spec-v2.yaml delete /v2/tags/{id} Delete a tag. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Tag Source: https://docs.serval.com/api-reference/tag-api/get-tag /sections/api-reference/openapi-spec-v2.yaml get /v2/tags/{id} Get a specific tag by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Subject Tags Source: https://docs.serval.com/api-reference/tag-api/list-subject-tags /sections/api-reference/openapi-spec-v2.yaml get /v2/tags/for-subject List the tags attached to a subject. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Resource tags, Role tags, Integration tags:** `apps:read`
**Form tags, Form Block tags, Workflow or skill tags:** `settings:read` | | Team-scoped API key | **Resource tags, Role tags, Integration tags:** `apps:read`
**Form tags, Form Block tags, Workflow or skill tags:** `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. Authorization follows the tagged subject. Granting permission to edit tag definitions alone does not authorize editing every tagged resource. # List Tags Source: https://docs.serval.com/api-reference/tag-api/list-tags /sections/api-reference/openapi-spec-v2.yaml get /v2/tags List all tags for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:read` | | Team-scoped API key | `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Remove Tag From Subject Source: https://docs.serval.com/api-reference/tag-api/remove-tag-from-subject /sections/api-reference/openapi-spec-v2.yaml post /v2/tags/remove-from-subject Detach a tag from a subject. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Resource tags, Role tags, Integration tags:** `apps:write`
**Form tags, Form Block tags:** `settings:write`
**Workflow tags:** `workflows:write`
**Skill tags:** `skills:write` | | Team-scoped API key | **Resource tags, Role tags, Integration tags:** `apps:write`
**Form tags, Form Block tags:** `settings:write`
**Workflow tags:** `workflows:write`
**Skill tags:** `skills:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. Authorization follows the tagged subject. Granting permission to edit tag definitions alone does not authorize editing every tagged resource. # Update Tag Source: https://docs.serval.com/api-reference/tag-api/update-tag /sections/api-reference/openapi-spec-v2.yaml put /v2/tags/{id} Update an existing tag. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Team Source: https://docs.serval.com/api-reference/team-api/create-team /sections/api-reference/openapi-spec-v2.yaml post /v2/teams Create a new team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Team Source: https://docs.serval.com/api-reference/team-api/delete-team /sections/api-reference/openapi-spec-v2.yaml delete /v2/teams/{id} Delete a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Non-branch team:** `teams:manage`
**Branch team:** Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Non-branch team:** The target team is not a branch. User OAuth requires an organization admin. Existing team deletion restrictions still apply. * **Branch team:** User OAuth requires an organization admin who originally created the branch. Branches with unavailable creator provenance cannot be deleted. # Get Team Source: https://docs.serval.com/api-reference/team-api/get-team /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{id} Get a specific team by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Teams Source: https://docs.serval.com/api-reference/team-api/list-teams /sections/api-reference/openapi-spec-v2.yaml get /v2/teams List all teams. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Team Source: https://docs.serval.com/api-reference/team-api/update-team /sections/api-reference/openapi-spec-v2.yaml put /v2/teams/{id} Update an existing team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Team Group Source: https://docs.serval.com/api-reference/team-group-api/create-team-group /sections/api-reference/openapi-spec-v2.yaml post /v2/teams/{team_id}/groups Bind a group to a team with a specified role. Every member of the group holds that role on the team. Purely additive: existing grants on the team, including other groups' bindings and direct user memberships, are unaffected. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Default request:** With a user OAuth token, setting custom\_role\_id also requires Edit Team Settings on the team. # Delete Team Group Source: https://docs.serval.com/api-reference/team-group-api/delete-team-group /sections/api-reference/openapi-spec-v2.yaml delete /v2/teams/{team_id}/groups/{group_id} Remove a group's role binding from a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Team Group Source: https://docs.serval.com/api-reference/team-group-api/get-team-group /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/groups/{group_id} Get a specific team group binding by team ID and group ID, or by composite ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Team Groups Source: https://docs.serval.com/api-reference/team-group-api/list-team-groups /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/groups List team group bindings. Filter by team_id and/or group_id; one of the two is required. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Team Group Source: https://docs.serval.com/api-reference/team-group-api/update-team-group /sections/api-reference/openapi-spec-v2.yaml put /v2/teams/{team_id}/groups/{group_id} Update the role a group holds on a team. Other grants on the team, including other groups' bindings and direct user memberships, are unaffected. Replaces whatever this group held on this team, including a custom role. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Default request:** With a user OAuth token, setting custom\_role\_id also requires Edit Team Settings on the team. # Create Team User Source: https://docs.serval.com/api-reference/team-user-api/create-team-user /sections/api-reference/openapi-spec-v2.yaml post /v2/teams/{team_id}/users Add a user to a team with a specified role. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Team User Source: https://docs.serval.com/api-reference/team-user-api/delete-team-user /sections/api-reference/openapi-spec-v2.yaml delete /v2/teams/{team_id}/users/{user_id} Remove a user from a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Team User Source: https://docs.serval.com/api-reference/team-user-api/get-team-user /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/users/{user_id} Get a specific team user by team ID and user ID, or by composite ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Team Users Source: https://docs.serval.com/api-reference/team-user-api/list-team-users /sections/api-reference/openapi-spec-v2.yaml get /v2/teams/{team_id}/users List team users. Filter by team_id and/or user_id. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Team User Source: https://docs.serval.com/api-reference/team-user-api/update-team-user /sections/api-reference/openapi-spec-v2.yaml put /v2/teams/{team_id}/users/{user_id} Update a team user's role. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `teams:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Add Ticket Relevant Asset Source: https://docs.serval.com/api-reference/ticket-api/add-ticket-relevant-asset /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{ticket_id}/relevant-assets Add a relevant asset to a ticket. Associates an entity from the asset store with the specified ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Archive Ticket Source: https://docs.serval.com/api-reference/ticket-api/archive-ticket /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{id}/archive Move a ticket into cold storage, removing it from most views. Non-archived descendant tickets are archived along with it. Reversible via Unarchive. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:archive` | | Team-scoped API key | `tickets:archive` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Connect to External Ticket Source: https://docs.serval.com/api-reference/ticket-api/connect-to-external-ticket /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{ticket_id}/connect Connect an existing Serval ticket to an existing external ticket in a sync channel. This establishes ongoing bidirectional sync between the tickets without creating a new external ticket. The external ticket must already exist in the target system. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Status Source: https://docs.serval.com/api-reference/ticket-api/create-status /sections/api-reference/openapi-spec-v2.yaml post /v2/statuses Create a ticket status for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Ticket Source: https://docs.serval.com/api-reference/ticket-api/create-ticket /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets Create a new ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. The requested team must be allowed. User callers have additional requester and ticket-type checks. # Create Ticket External Messages Source: https://docs.serval.com/api-reference/ticket-api/create-ticket-external-messages /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{ticket_id}/external-messages Register Serval messages as already present in an external channel. This records external message links so the egresser will not re-send those messages to the external system. Use this after posting a summary of prior conversation to an external ticket to prevent the individual historical messages from being replayed. Pass a single message to register one, or many to register in bulk. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Ticket Message Source: https://docs.serval.com/api-reference/ticket-api/create-ticket-message /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{ticket_id}/messages Create a new message in a ticket. Set is_internal_note to post an internal note visible only to team members. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Ticket Subscribers Source: https://docs.serval.com/api-reference/ticket-api/create-ticket-subscribers /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{ticket_id}/subscribers Add subscribers to a ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Status Source: https://docs.serval.com/api-reference/ticket-api/delete-status /sections/api-reference/openapi-spec-v2.yaml delete /v2/statuses/{id} Delete an unused, non-default ticket status. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Ticket Source: https://docs.serval.com/api-reference/ticket-api/delete-ticket /sections/api-reference/openapi-spec-v2.yaml delete /v2/tickets/{id} Hard-delete a ticket and its associated messages plus workflow run history for data-retention purposes. Irreversible. Does not cascade to sub-tickets — callers must iterate them themselves. ## Authentication and permissions > **Token requirements:** **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:admin` | | Team-scoped API key | `tickets:admin` | | User-based token (OAuth) | Unsupported | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Permanently delete:** The team must enable hard-delete. A team manager cannot issue the tickets:admin permission; an organization admin can issue a restricted key with it. # Delete Ticket Subscriber Source: https://docs.serval.com/api-reference/ticket-api/delete-ticket-subscriber /sections/api-reference/openapi-spec-v2.yaml delete /v2/tickets/{ticket_id}/subscribers/{user_id} Remove a subscriber from a ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Disconnect from External Ticket Source: https://docs.serval.com/api-reference/ticket-api/disconnect-from-external-ticket /sections/api-reference/openapi-spec-v2.yaml delete /v2/tickets/{ticket_id}/disconnect/{source_id} Disconnect a Serval ticket from an external sync channel. This stops bidirectional sync with the specified external system. Useful when moving a ticket from one channel to another (e.g., email to Slack DM). The external ticket connection is soft-deleted, preserving historical data. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Category Source: https://docs.serval.com/api-reference/ticket-api/get-category /sections/api-reference/openapi-spec-v2.yaml get /v2/categories/{id} Get a category (or subcategory) by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Priority Source: https://docs.serval.com/api-reference/ticket-api/get-priority /sections/api-reference/openapi-spec-v2.yaml get /v2/priorities/{id} Get a priority by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Status Source: https://docs.serval.com/api-reference/ticket-api/get-status /sections/api-reference/openapi-spec-v2.yaml get /v2/statuses/{id} Get a ticket status by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Ticket Source: https://docs.serval.com/api-reference/ticket-api/get-ticket /sections/api-reference/openapi-spec-v2.yaml get /v2/tickets/{id} Get a specific ticket by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Ticket Custom Field Values Source: https://docs.serval.com/api-reference/ticket-api/get-ticket-custom-field-values /sections/api-reference/openapi-spec-v2.yaml get /v2/tickets/{ticket_id}/custom-field-values Get the custom field values that have been explicitly set on a ticket. Returns only fields with values — if no values have been set, both lists will be empty. To discover all available custom field definitions for a team, use the List Custom Field Options endpoint instead. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Ticket Relationship Source: https://docs.serval.com/api-reference/ticket-api/get-ticket-relationship /sections/api-reference/openapi-spec-v2.yaml get /v2/ticket-relationships/{id} Get a ticket relationship by its ID. The relationship object contains the ticket_id, related_ticket_id, and relationship_type (linked, duplicate, or parent). ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Link Tickets Source: https://docs.serval.com/api-reference/ticket-api/link-tickets /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{ticket_id}/linked-tickets Link two tickets together with a linked relationship. Both tickets must be in the same team. The relationship is symmetric: each ticket shows the other as a related ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Categories Source: https://docs.serval.com/api-reference/ticket-api/list-categories /sections/api-reference/openapi-spec-v2.yaml get /v2/categories List categories (including nested subcategories) for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Labels Source: https://docs.serval.com/api-reference/ticket-api/list-labels /sections/api-reference/openapi-spec-v2.yaml get /v2/labels List labels for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Priorities Source: https://docs.serval.com/api-reference/ticket-api/list-priorities /sections/api-reference/openapi-spec-v2.yaml get /v2/priorities List priorities for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Statuses Source: https://docs.serval.com/api-reference/ticket-api/list-statuses /sections/api-reference/openapi-spec-v2.yaml get /v2/statuses List statuses for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Ticket External Messages Source: https://docs.serval.com/api-reference/ticket-api/list-ticket-external-messages /sections/api-reference/openapi-spec-v2.yaml get /v2/tickets/{ticket_id}/external-messages List all origin external messages for a ticket. These are messages that originated from external systems and were synced into Serval. This helps you understand which messages came from which external channels. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Ticket External Tickets Source: https://docs.serval.com/api-reference/ticket-api/list-ticket-external-tickets /sections/api-reference/openapi-spec-v2.yaml get /v2/tickets/{ticket_id}/external-tickets List all external tickets linked to a Serval ticket. This shows all the external systems (Jira, Linear, ServiceNow, etc.) where this ticket is synced. Use the is_origin field to identify the original source of the ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Ticket Feedback Source: https://docs.serval.com/api-reference/ticket-api/list-ticket-feedback /sections/api-reference/openapi-spec-v2.yaml get /v2/ticket-feedback List feedback items across tickets for a team. Only includes feedback that has been responded to. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Ticket Messages Source: https://docs.serval.com/api-reference/ticket-api/list-ticket-messages /sections/api-reference/openapi-spec-v2.yaml get /v2/tickets/{ticket_id}/messages List messages for a ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Team messages:** `tickets:read`
**Requester messages:** Unsupported | | Team-scoped API key | **Team messages:** `tickets:read`
**Requester messages:** Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Requester messages:** The caller must be authorized for the ticket requester. Internal notes have separate visibility checks. # List Ticket Relevant Assets Source: https://docs.serval.com/api-reference/ticket-api/list-ticket-relevant-assets /sections/api-reference/openapi-spec-v2.yaml get /v2/tickets/{ticket_id}/relevant-assets List all relevant assets associated with a ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Ticket Subscribers Source: https://docs.serval.com/api-reference/ticket-api/list-ticket-subscribers /sections/api-reference/openapi-spec-v2.yaml get /v2/tickets/{ticket_id}/subscribers List all subscribers for a ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Tickets Source: https://docs.serval.com/api-reference/ticket-api/list-tickets /sections/api-reference/openapi-spec-v2.yaml get /v2/tickets List tickets for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Move Ticket To Team Source: https://docs.serval.com/api-reference/ticket-api/move-ticket-to-team /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{ticket_id}/move-to-team Move a ticket to a different team. The help agent re-runs under the destination team's configuration. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Move between teams:** Requires UPDATE\_TICKET on both the source and destination teams. A key restricted to one team cannot move a ticket to another team. # Promote Ticket To Major Incident Source: https://docs.serval.com/api-reference/ticket-api/promote-ticket-to-major-incident /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{id}/promote-to-major-incident Promote an incident in place to a major incident, recording the optional reason on the ticket's activity log and carrying existing custom-field values onto the major-incident field set. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Reclassify Ticket Source: https://docs.serval.com/api-reference/ticket-api/reclassify-ticket /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{id}/reclassify Reclassify a ticket in place between request and incident, recording the optional reason on the ticket's activity log. Promotion to a major incident is a separate command. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Remove Ticket Relevant Asset Source: https://docs.serval.com/api-reference/ticket-api/remove-ticket-relevant-asset /sections/api-reference/openapi-spec-v2.yaml delete /v2/tickets/{ticket_id}/relevant-assets/{asset_id} Remove a relevant asset from a ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Search Ticket Messages Source: https://docs.serval.com/api-reference/ticket-api/search-ticket-messages /sections/api-reference/openapi-spec-v2.yaml post /v2/ticket-messages/search Search messages across tickets with filters for team, ticket, author, author role, and creation time range. This is the single-request alternative to listing tickets and calling List Ticket Messages per ticket — e.g. all messages authored by given team members in a given week, regardless of when their tickets were opened. Searches messages on non-archived tickets the caller can view; results are ordered newest first. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | **Search specified teams:** `tickets:read`
**Search the organization:** Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Search specified teams:** Supply team\_ids. Every requested team must be allowed. * **Search the organization:** Omitting team\_ids searches the organization and requires an organization-scoped key. # Search Tickets Source: https://docs.serval.com/api-reference/ticket-api/search-tickets /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/search Search tickets with filters. Supports filtering by team, assignment, status, escalation level, time range, external ticket key, and parent_ticket_ids (all children of the given tickets — e.g. every task of a journey — matching the parent_ticket_id field on the ticket payload). ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | **Search specified teams:** `tickets:read`
**Search the organization:** Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Search specified teams:** Supply team\_ids. Every requested team must be allowed. * **Search the organization:** Omitting team\_ids searches the organization and requires an organization-scoped key. # Set Ticket Custom Field Values Source: https://docs.serval.com/api-reference/ticket-api/set-ticket-custom-field-values /sections/api-reference/openapi-spec-v2.yaml put /v2/tickets/{ticket_id}/custom-field-values Set custom field values on a ticket. Uses the ticket's extension entity to store field values. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Submit Ticket Feedback Source: https://docs.serval.com/api-reference/ticket-api/submit-ticket-feedback /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{ticket_id}/feedback Submit a user's feedback (CSAT) on a ticket. Defaults to the ticket's requester; pass user_id to submit for another user. Answers the ticket's pending feedback request for that user when one exists, otherwise records new feedback. The response variant (thumbs or detailed) must match the team's configured feedback question format. Submitting again after the user has already answered replaces their rating; an omitted text_feedback keeps the existing comment. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Sync Ticket to Channel Source: https://docs.serval.com/api-reference/ticket-api/sync-ticket-to-channel /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{ticket_id}/sync Sync an existing Serval ticket to a channel by creating an external ticket in that channel and establishing ongoing bidirectional sync. Supports ticket sources (Jira, Linear, ServiceNow, etc.) and direct messaging channels (Slack DM, Email). ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Unarchive Ticket Source: https://docs.serval.com/api-reference/ticket-api/unarchive-ticket /sections/api-reference/openapi-spec-v2.yaml post /v2/tickets/{id}/unarchive Restore a ticket from cold storage. Fails if the ticket's parent is still archived. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:archive` | | Team-scoped API key | `tickets:archive` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Priority Source: https://docs.serval.com/api-reference/ticket-api/update-priority /sections/api-reference/openapi-spec-v2.yaml patch /v2/priorities/{id} Update a priority's display name, description, or AI selectability. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Status Source: https://docs.serval.com/api-reference/ticket-api/update-status /sections/api-reference/openapi-spec-v2.yaml patch /v2/statuses/{id} Update a ticket status. Omitted fields are preserved; empty color or emoji values clear their overrides. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Ticket Source: https://docs.serval.com/api-reference/ticket-api/update-ticket /sections/api-reference/openapi-spec-v2.yaml put /v2/tickets/{id} Update an existing ticket. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:write` | | Team-scoped API key | `tickets:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. User callers setting another requester need SET\_TICKET\_REQUESTER. Resource and ticket-type restrictions still apply. # List Topics Source: https://docs.serval.com/api-reference/topic-api/list-topics /sections/api-reference/openapi-spec-v2.yaml get /v2/topics List the AI-generated topic taxonomy for a team. Topics form a hierarchy representing common themes across tickets. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `tickets:read` | | Team-scoped API key | `tickets:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create User Source: https://docs.serval.com/api-reference/user-api/create-user /sections/api-reference/openapi-spec-v2.yaml post /v2/users Create a new user. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Create a member or guest:** `users:manage`
**Create an organization admin:** `org:admin` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete User Source: https://docs.serval.com/api-reference/user-api/delete-user /sections/api-reference/openapi-spec-v2.yaml delete /v2/users/{id} Delete a user. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Current User Source: https://docs.serval.com/api-reference/user-api/get-current-user /sections/api-reference/openapi-spec-v2.yaml get /v2/me Get the current authenticated user's profile, including their organization role and team memberships with roles. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | Unsupported | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. * **Current user:** Requires a user identity. API keys do not have a current user. # Get User Source: https://docs.serval.com/api-reference/user-api/get-user /sections/api-reference/openapi-spec-v2.yaml get /v2/users/{id} Get a specific user by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:read` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List User Phone Numbers Source: https://docs.serval.com/api-reference/user-api/list-user-phone-numbers /sections/api-reference/openapi-spec-v2.yaml get /v2/users/{user_id}/phone-numbers List current phone assignments and their login trust. Existing, imported and newly added numbers are untrusted by default. Select an assignment by e164, is_primary or label rather than list order. ## Authentication and permissions > **Token requirements:** **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:read` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Unsupported | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Users Source: https://docs.serval.com/api-reference/user-api/list-users /sections/api-reference/openapi-spec-v2.yaml get /v2/users List all users. Pass emails to resolve specific users by email address (exact, case-insensitive) instead of paging the whole directory; repeat the parameter to resolve a batch in one request. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:read` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Reactivate User Source: https://docs.serval.com/api-reference/user-api/reactivate-user /sections/api-reference/openapi-spec-v2.yaml post /v2/users/{id}/reactivate Reactivate a previously deactivated user, restoring their organization membership. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Reactivate a member or guest:** `users:manage`
**Reactivate an organization admin:** `org:admin` + `users:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Set User Phone Login Trust Source: https://docs.serval.com/api-reference/user-api/set-user-phone-login-trust /sections/api-reference/openapi-spec-v2.yaml put /v2/users/{user_id}/phone-numbers/{phone_number_id}/login-trust Explicitly grant or revoke magic-link login trust for the current phone assignment. This does not grant helpdesk verification. Removing and re-adding a phone requires trusting its new phone number ID. Directory replacement or clearing of a primary phone revokes its login trust. Manual primary selection preserves trust. Existing browser sessions are not revoked. ## Authentication and permissions > **Token requirements:** **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Unsupported | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update User Source: https://docs.serval.com/api-reference/user-api/update-user /sections/api-reference/openapi-spec-v2.yaml put /v2/users/{id} Update an existing user. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create User Relationship Source: https://docs.serval.com/api-reference/user-relationship-api/create-user-relationship /sections/api-reference/openapi-spec-v2.yaml post /v2/user-relationships Create or update a user relationship. If a relationship already exists, it will be updated. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete User Relationship Source: https://docs.serval.com/api-reference/user-relationship-api/delete-user-relationship /sections/api-reference/openapi-spec-v2.yaml delete /v2/user-relationships/{user_id} Delete a user relationship. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:manage` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get User Relationship Source: https://docs.serval.com/api-reference/user-relationship-api/get-user-relationship /sections/api-reference/openapi-spec-v2.yaml get /v2/user-relationships/{user_id} Get a user's relationship of the given type (e.g. their manager). Returns 404 if the user has no relationship of that type. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:read` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List User Relationships Source: https://docs.serval.com/api-reference/user-relationship-api/list-user-relationships /sections/api-reference/openapi-spec-v2.yaml get /v2/user-relationships List user relationships. Filter by user_id, related_user_id (a manager's direct reports), and/or relationship_type. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `users:read` | | Team-scoped API key | Unsupported | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Workflow Source: https://docs.serval.com/api-reference/workflow-api/create-workflow /sections/api-reference/openapi-spec-v2.yaml post /v2/workflows Create a new workflow for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Save a draft:** `workflows:write`
**Publish:** `workflows:deploy` + `workflows:write` | | Team-scoped API key | **Save a draft:** `workflows:write`
**Publish:** `workflows:deploy` + `workflows:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Workflow Source: https://docs.serval.com/api-reference/workflow-api/delete-workflow /sections/api-reference/openapi-spec-v2.yaml delete /v2/workflows/{id} Delete a workflow. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:write` | | Team-scoped API key | `workflows:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Workflow Source: https://docs.serval.com/api-reference/workflow-api/get-workflow /sections/api-reference/openapi-spec-v2.yaml get /v2/workflows/{id} Get a specific workflow by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:read` | | Team-scoped API key | `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Workflow Versions Source: https://docs.serval.com/api-reference/workflow-api/list-workflow-versions /sections/api-reference/openapi-spec-v2.yaml get /v2/workflows/{workflow_id}/versions List the version history of a workflow. By default returns only published versions (newest first). Pass include_unpublished_drafts=true to also include unpublished drafts. Each version's id can be passed as workflow_version_id to StartWorkflowRun to run that specific version. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:read` | | Team-scoped API key | `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Workflows Source: https://docs.serval.com/api-reference/workflow-api/list-workflows /sections/api-reference/openapi-spec-v2.yaml get /v2/workflows List all workflows for a team. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:read` | | Team-scoped API key | `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Resolve Scoped IDs Source: https://docs.serval.com/api-reference/workflow-api/resolve-scoped-ids /sections/api-reference/openapi-spec-v2.yaml post /v2/scoped-ids/resolve Resolve team-scoped ids (wf_/skill_/ent_/form_) to their resource UUID, display name, and kind within a team. Unresolvable ids are omitted. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Workflow references:** `workflows:read`
**Skill references:** `skills:read`
**Role references, Resource references, Integration references:** `apps:read`
**Form references, Access-policy references, Approval-procedure references:** `settings:read` | | Team-scoped API key | **Workflow references:** `workflows:read`
**Skill references:** `skills:read`
**Role references, Resource references, Integration references:** `apps:read`
**Form references, Access-policy references, Approval-procedure references:** `settings:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. A request containing several resource kinds requires every corresponding read permission. # Update Workflow Source: https://docs.serval.com/api-reference/workflow-api/update-workflow /sections/api-reference/openapi-spec-v2.yaml put /v2/workflows/{id} Update an existing workflow. Fields left out of the request keep their current values. Set approval_procedure_id to the ID of a named approval procedure to require its approval before each run, or to an empty string to remove the workflow's approval; omit it to leave approval unchanged. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | **Save a draft:** `workflows:write`
**Publish:** `workflows:deploy` + `workflows:write` | | Team-scoped API key | **Save a draft:** `workflows:write`
**Publish:** `workflows:deploy` + `workflows:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Create Workflow Approval Procedure Source: https://docs.serval.com/api-reference/workflow-approval-procedure-api/create-workflow-approval-procedure /sections/api-reference/openapi-spec-v2.yaml post /v2/workflows/{workflow_id}/approval-procedures Create a new approval procedure for a workflow. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Delete Workflow Approval Procedure Source: https://docs.serval.com/api-reference/workflow-approval-procedure-api/delete-workflow-approval-procedure /sections/api-reference/openapi-spec-v2.yaml delete /v2/workflows/{workflow_id}/approval-procedures/{id} Delete an approval procedure for a workflow. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `settings:write` | | Team-scoped API key | `settings:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Workflow Approval Procedure Source: https://docs.serval.com/api-reference/workflow-approval-procedure-api/get-workflow-approval-procedure /sections/api-reference/openapi-spec-v2.yaml get /v2/workflows/{workflow_id}/approval-procedures/{id} Get a specific approval procedure by ID for a workflow. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:read` | | Team-scoped API key | `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Workflow Approval Procedures Source: https://docs.serval.com/api-reference/workflow-approval-procedure-api/list-workflow-approval-procedures /sections/api-reference/openapi-spec-v2.yaml get /v2/workflows/{workflow_id}/approval-procedures List all approval procedures for a workflow. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:read` | | Team-scoped API key | `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Update Workflow Approval Procedure Source: https://docs.serval.com/api-reference/workflow-approval-procedure-api/update-workflow-approval-procedure /sections/api-reference/openapi-spec-v2.yaml put /v2/workflows/{workflow_id}/approval-procedures/{id} Update an existing approval procedure for a workflow. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:write` | | Team-scoped API key | `workflows:write` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Count Workflow Runs Source: https://docs.serval.com/api-reference/workflow-run-api/count-workflow-runs /sections/api-reference/openapi-spec-v2.yaml post /v2/workflow-runs/count Count workflow runs matching the same filters as Search Workflow Runs (workflow ID, status, user IDs, time range, linked ticket, parent run, include_child_runs, include_runs_with_linked_ticket). Use this instead of paging the full result set when only the total is needed — e.g. dashboard tiles or sizing a backfill before running it. The count walks the full filtered set, so latency scales with how many rows match; on teams with millions of runs, narrow the count with created_after/created_before (very broad counts may hit the server's query timeout). ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:read` | | Team-scoped API key | `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Workflow Run Source: https://docs.serval.com/api-reference/workflow-run-api/get-workflow-run /sections/api-reference/openapi-spec-v2.yaml get /v2/workflow-runs/{id} Get a specific workflow run by ID. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:read` | | Team-scoped API key | `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Get Workflow Run Task Source: https://docs.serval.com/api-reference/workflow-run-api/get-workflow-run-task /sections/api-reference/openapi-spec-v2.yaml get /v2/workflow-runs/{workflow_run_id}/tasks/{step_number} Get the full (size-capped) input and output for a single task (step) of a workflow run. Use after ListWorkflowRunTasks to drill into a specific step when debugging a failure. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:read` | | Team-scoped API key | `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Workflow Run Tasks Source: https://docs.serval.com/api-reference/workflow-run-api/list-workflow-run-tasks /sections/api-reference/openapi-spec-v2.yaml get /v2/workflow-runs/{workflow_run_id}/tasks List the tasks (steps) of a workflow run, ordered by step, with truncated input/output previews and a resolved outcome per step. Paginated. Use this to find the failing step within a run, then call GetWorkflowRunTask for that step's full input/output. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:read` | | Team-scoped API key | `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # List Workflow Runs Source: https://docs.serval.com/api-reference/workflow-run-api/list-workflow-runs /sections/api-reference/openapi-spec-v2.yaml get /v2/workflow-runs List all workflow runs for a team, ordered by created_at desc. For filtering (by workflow_id, status, user, time range, or linked ticket), use POST /v2/workflow-runs/search instead. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:read` | | Team-scoped API key | `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # Search Workflow Runs Source: https://docs.serval.com/api-reference/workflow-run-api/search-workflow-runs /sections/api-reference/openapi-spec-v2.yaml post /v2/workflow-runs/search Search workflow runs with filters. Supports filtering by workflow ID, status, user IDs, time range, linked ticket, and parent_workflow_run_id. Set include_child_runs=false to exclude child runs (runs spawned by another run), or include_runs_with_linked_ticket=true to return only ticket-linked runs — both avoid paging rows a caller would otherwise discard client-side. To investigate a run's sub-workflows, search with parent_workflow_run_id set to that run's id (combine with statuses=[FAILED] to find failing children), then recurse into each child run. ## Authentication and permissions > **Token requirements:** **User-based token (OAuth)** or **Organization-scoped API key** or **Team-scoped API key**. > > Send a bearer access token for one of these identities. The permissions and resource restrictions below also apply. | Credential | Access requirements | | - | - | | Organization-scoped API key | `workflows:read` | | Team-scoped API key | `workflows:read` | | User-based token (OAuth) | Supported, subject to permissions | Permissions joined by **+** are all required; **or** separates alternatives. Full-access keys still cannot call endpoints marked unsupported. Team keys must allow every team checked by the request. OAuth access depends on the user’s roles and resource access. # User Access Reviews Source: https://docs.serval.com/sections/access-management/access-reviews Run structured user access reviews: scope who and what to review, assign reviewers to certify or deny each grant, and revoke access that's no longer justified User access reviews are in Beta. A *user access review* (UAR) lets you certify that users still need the access they have. You define what to review, Serval assigns reviewers, and each reviewer certifies, denies, or skips every account and role grant in scope. When the review is done, you revoke the access that was denied. UARs produce access-certification evidence for SOC 2, ISO 27001, and similar audits. ## How a UAR works A UAR moves through four stages: * **Draft**: you're still setting up the details and scope. * **Prepared**: Serval has taken a snapshot of every grant in scope and assigned reviewers. The UAR is ready to launch. * **Running**: assigned reviewers are working through their tasks and recording decisions. * **Completed**: every item has a decision, or the owner ended the review. You can then revoke denied access. Two roles are involved: * The *review owner* creates and runs the review. Owning a review requires a Manager or org admin role. * *Reviewers* are assigned to individual grants and record decisions. Any member of the organization can be assigned as a reviewer. ## Create a UAR From **Access → Access Reviews**, click **New Review**. The setup is a three-step wizard, and Serval saves your progress as you go. ### Step 1: Details * Enter a **Review name** (for example, "SOC 2 Quarterly Review") and an optional **Description** of the review purpose. * Select the **Target completion date** you want the review finished by. Serval uses it to schedule reminders. * Set the **Review policy** to define how the UAR runs: reviewer steps, whether comments are required on decisions, and whether people can review their own access. You have two options: * Leave it on **None — Serval defaults** to have the review owner review every item with comments optional. * Pick a policy your team has created, or create a new one. For more information, see [Review policies](#review-policies). * Optionally, under **AI insights**, turn on **Generate AI insights** to have Serval suggest a decision for each task after launch. For more information, see [AI insights](#ai-insights). New Access Review wizard on the Details step, showing Review name, Description, Target completion date, and a Review policy set to None — Serval defaults ### Step 2: Scope Your scope filters down the grants that will be reviewed. Choose one of two scope options, then click **Configure scope**: * **Manual scope**: hand-pick the teams, applications, resources, and roles to review. * **Tag-based scope**: review everything carrying the tags you select within a single team. Scope step with Manual scope selected and one application added Scope step with Tag-based scope selected, a tag applied, and the matching applications listed Reviews cover the grants Serval already knows about. If Serval doesn't automatically track who has access to an application, import the current grants first so they're in scope. Open the application, go to its **Access Management** view, open the **⋯** (more actions) menu, and choose **Import grants from a file**. Upload either a CSV export (up to 15 MiB and 500,000 rows) or a PNG, JPEG, or WebP screenshot of the application's members list (up to 10 MiB). For a CSV, map each row's account and role; for a screenshot, Serval reads the accounts, names, roles, and statuses it shows. Review the resulting rows, then commit. Past imports are listed under the application's **Grant imports** settings. ### Step 3: Prepare and launch When you continue, Serval prepares a point-in-time snapshot of every account-and-role grant that matches your scope and assigns reviewers to each one based on your review policy. If access changes, those changes aren't reflected in the snapshot until you prepare a new one. Click **Back** to return to the scope step, adjust the details or scope, and click **Prepare review** again. If the scope changed, Serval asks you to confirm and then replaces the earlier snapshot, including any reviewer changes you made to it. If the scope didn't change, you return to the same prepared review. The prepared list shows each **Account**, the **Role** it holds, and the assigned **Reviewers**. Drafts and prepared-but-unlaunched reviews are saved to your team, so you can continue setting up a review, or click **Back** to re-scope it, from any browser until it launches. Every grant must have at least one reviewer per step before you can launch. When everything is assigned, click **Launch Test**. Prepare step listing the prepared account-role grants with assigned reviewers ## Review policies A review policy defines the way in which a UAR runs: who reviews each grant, whether reviewers must comment, and whether people can review their own access. Review policies are managed under **Settings → Review Policies**. You can access the review policy creation flow in two different locations: * When setting the **Review policy** in the new UAR creation flow, click **+ Create policy** * Navigate to **Settings → Review Policies** and click **+ Create policy** To create the policy, enter the following information: * **Policy Name** and **Policy Description**: a name and a one-line note about when to use the policy. * **Require comments on decisions** (**Yes** / **No**): whether a reviewer must add a justification with every decision. * **Allow self-review** (**Yes** / **No**): whether a reviewer can decide on their own access. Then define the **reviewer steps** that set who reviews, in order. Click **Create policy** to save. A review **pins** the policy it was prepared with, so later edits only affect future reviews. You can mark one policy as your team's default. When a review uses **None** (the Serval default), the review owner reviews every grant, comments are optional, and self-review is allowed. Create review policy dialog with Policy Name, Require comments on decisions, Allow self-review, and reviewer steps ## Complete a UAR (reviewers) Reviewers work from the **My pending tasks** tab of a running UAR. For each grant, choose one decision: * **Certify**: the access is still appropriate. Keep it. * **Deny**: the access is no longer justified. Mark it for revocation. * **Skip**: don't make a decision on this grant. My pending tasks tab showing grants with Certify, Deny, and Skip actions per row Comments are optional unless the review's policy requires them, in which case you, the reviewer, must add a comment justifying the decision before it's recorded. Reviewers are reminded automatically: 7 days before the due date, 1 day before, on the due date, and weekly while overdue. Reminders reach reviewers in Slack, Microsoft Teams, and email. ## Manage a UAR (review owners) The review detail page gives the owner a full view through several tabs: * **All review tasks**: every grant, its reviewers, and its **Final decision** (Pending, Certified, Denied, or Skipped). * **My pending tasks**: grants awaiting your own decision. * **Submitted**: decisions already recorded. * **Configuration**: the review's scope, its pinned policy, its notification settings, and the **Generate AI insights** toggle. * **Reports**: generate and download the audit export (see [Reports](#reports)). The grant list on **All review tasks** and **My pending tasks** has three views. **List** is a flat, paged table. **By app** nests grants under each application and resource. **By user** nests grants under each person, so you can see every role one account holds across the review and how many of their grants are already decided. Expand a person to work through their grants, or select the whole group at once. Use **All reviewers** on **All review tasks** to narrow the grant list to one or more assigned reviewers. The control shows who is selected, and the progress summary updates to match the filtered list. **Clear filters** appears next to the filters whenever any filter or search is active and resets all of them at once. If a reviewer has been deactivated while they still hold review items, a banner above the list says so. **Show their items** on that banner applies the reviewer filter to the deactivated reviewers found in the rows loaded so far, so you can reassign the affected grants. Owners have extra controls: * **Override decisions**: change a reviewer's decision on any grant. * **End review**: finish a review before every item is decided. You choose whether to skip the remaining items or deny them. You can also reopen or cancel a review. All review tasks tab showing accounts, roles, reviewers, and Final decision status, with an Override decisions control ## AI insights AI insights are opt-in per review and off by default. A review with the toggle off runs exactly as described above. When **Generate AI insights** is on, Serval generates a suggestion for each task once the review launches: a suggested action, a one-line summary, a set of insight bullets, and a suggested comment. Suggestions are advice. Nothing is recorded until a reviewer acts on the task. Suggestions are built only from the access data Serval already holds for the grant: how and when it was granted, the business justification and messages on the original access request, the last sign-in to the application, whether the account or the person is deactivated, how many peers under the same manager or in the same department hold the same role, and the decision an earlier review recorded on the same grant. ### Turn on AI insights * **When you create the review**: on the **Details** step, under **AI insights**, turn on **Generate AI insights**. The launch screen confirms that AI insights will be generated for every task after launch. * **On a running review**: open the **Configuration** tab and turn on the same toggle. Serval asks you to confirm, because generation starts for every open task. Generation runs once after launch and isn't re-run. The **Configuration** tab shows progress while insights are generated and the number of tasks with insights when it finishes. Turning the toggle off hides every suggestion, including ones already generated. Turning it back on generates insights only for tasks that don't have one yet. ### Suggested actions Each task gets one of three suggestions: * **Certify**: the signals support keeping the access. * **Revoke**: the signals point to removing the access. Accepting it records a **Deny** decision. * **Flagged**: the signals are mixed or too thin to suggest a decision. A flagged task has no suggested comment and needs your own decision. ### Review with AI insights * **Insight column**: a one-line summary for each task. A task whose insight hasn't been generated yet shows a dash. * **Accept suggestion**: the decision button highlights the suggested action. Click **Accept suggestion** to record it with the suggested comment as your justification, or open the decision dialog to edit the comment first. If the review's policy requires comments, the suggested comment satisfies it — on the rare task that has none, record your own. * **Insights**: expand a task to read the insight bullets and the **Suggested comment**. Green bullets support keeping the access, red bullets argue for removing it, and the rest add neutral context. * **Current access**: the expanded task also lists the other applications the person currently has access to. **View all** opens the full list. * **Filter by suggestion**: the **All suggestions** filter narrows the table to the tasks Serval suggested to **Certify** or **Revoke**, or **Flagged**. * **Accept in bulk**: select tasks and click **Accept suggestions** to accept every selected suggestion at once. Flagged tasks and tasks without an insight are skipped and stay selected. A decision made by accepting a suggestion is marked **Accepted AI suggestion** on the task's status, so the audit trail shows which decisions were AI-assisted. ## Decisions and remediation A **Denied** decision records that access should be removed. It doesn't remove the access on its own. When the review is complete, the owner selects the denied grants and runs remediation to actually deprovision them. This keeps the review separate from remediation, so you can complete and audit a review before any access is touched. ## Reports From the **Reports** tab, **Generate report** produces an audit export; its menu chooses the format. XLSX workbooks include a summary, resources in scope, the full per-grant decision matrix, and revocations. CSV exports contain the per-grant decision matrix for importing into analysis and compliance tools. ## Related Roles, access policies, and provisioning. Control who can request which roles. # Admin Quickstart Source: https://docs.serval.com/sections/access-management/admin-quickstart Set up just-in-time access management for your applications in minutes Set up just-in-time (JIT) access management to control who requests application access, duration limits, approvals, and provisioning methods. [Connect an application](#1-connect-an-application), [configure roles](#2-configure-roles), [test requests](#3-test-access-requests), then [audit and monitor access](#4-audit-and-monitor-access). Repeat this process for every application you want to manage. With access management, enforce least-privilege, role-based access control. *** ## 1. Connect an Application Connect the first application you want to manage. You can find instructions for each application in the [integrations overview](https://docs.serval.com/sections/integrations/overview). Use Serval's native integrations for common applications like GitHub, Slack, AWS, and more Build a custom integration for applications not in our library If you only want to use an application for access management and don't need it for workflows, you can create a lightweight connection without setting up the full integration. Click "Connect an app" and fill in the name of the app as a placeholder for a full integration connection. If you haven't set up your Slack or Teams integration as a help desk yet, we recommend doing this now. You can use it to test roles and permissioning more efficiently. *** ## 2. Configure Roles Navigate to the application you'd like to configure access to and identify which roles you'd like to configure first. ### Access layers In Serval, you can configure role access at two levels: Configure role access to an application under "Integrations" **Example:** Admin, Member, Viewer or Billing Manager access to GitHub Create a custom resource and configure role access within it under "Resources" **Example:** Add the engineering GitHub team as a resource and set up roles within that team ### Configure roles three ways Serval offers [manual role setup](#manually-configuring-roles) (most common), [importing roles from your IdP](#importing-roles-from-your-idp), and [auto-filled roles](#auto-filled-roles). ### Manually configuring roles Navigate to the relevant team from the sidebar, click **Access Management**, open the **Apps** tab, then select the relevant application. **Best Practice:** Connect your IdP before provisioning access. This lets you provision access via Linked Groups, which automatically adds and removes users from IdP groups as access is granted and expires. **Creating roles** * For application roles: Click "New Role" in "App Access" * For resource roles: * Click "Create a Custom Resource," fill in the Name and Description, then click "New Role" in that resource * Click into an existing resource and click "New Role" in that resource 1. Name the role (e.g., Member, Admin, Editor) 2. Add a description of what type of access this is. Serval will use this to guide users to the right access level Configure the following for each role: * [**Access Profiles**](https://docs.serval.com/sections/access-management/configuration/access-profiles)**:** Which groups can request this role * [**Access Policies**](https://docs.serval.com/sections/access-management/configuration/access-policies)**:** Rules for access requests (duration, business justification, approval process) * [**Provisioning Methods**](https://docs.serval.com/sections/access-management/configuration/access-provisioning)**:** How access is granted (manual task, SCIM, custom workflow, API) ### Importing roles from your IdP Once you've [connected an IdP](https://docs.serval.com/sections/access-management/configuration/connect-idp) to Serval, Serval will populate suggested roles based on the groups you have set up in that IdP. 1. Serval matches IdP group names to potential roles and lets you import them. 2. After importing a role, configure provisioning through Linked Groups, Custom Workflows, or Direct (via API). ### Auto-filled roles For Linear and Ramp, Serval automatically identifies default application roles and adds them upon connection. * Navigate to the application * Configure each auto-filled role with the appropriate profiles, policies, and provisioning methods. *** ## 3. Test Access Requests Use your configured help desk (or the ticketing system in app.serval.com) to verify your setup works as intended. **Recommended testing approach:** Set up your Slack or Teams integration first if you haven't already. Testing through conversational interfaces is faster and mirrors how users will actually interact with the system. You can verify the complete flow—request, approval routing, provisioning, and notifications—in a single thread. Request access to one of your configured roles through Slack, Teams, or the Serval interface Check that: * The request routes to the correct approver * Business justification requirements work as expected * Access is provisioned correctly * Temporary access expires on schedule Adjust policies, profiles, or provisioning methods based on test results *** ## 4. Audit and Monitor Access Once your access management system is in use, monitor access and view access logs to ensure compliance and identify potential security issues. Learn more about [access reviews](/sections/access-management/reviews/access-reviews) here. ## 5. Manage Profiles and Policies Centrally Manage profiles and policies centrally to maintain uniform access controls across your organization. See [access profiles](/sections/access-management/configuration/access-profiles) and [access policies](/sections/access-management/configuration/access-policies) for details. Open the team in the sidebar, then go to **Settings** → **Access Profiles** or **Access Policies**. From this view, you can: * Set default profiles and policies * Configure centralized access controls * Manage role assignments *** ## Special Cases Upon connecting your IdP, Serval ingests all groups from that IdP and stores them as resources with a "member" default role. These resources function as groups across Serval and are not treated as standard resources. You should not manage role access through Serval for: * Slack channels * Google groups * Okta groups * Email distribution lists Manage these through workflows, not access management. Manual configuration for each group doesn't scale. Rely on IdP audits for full access trails. *** ## Example Scenario: Starter use case for access management Your organization uses Okta, Google, Slack, and GitHub. Your Engineering team uses AWS databases. 1. Connect your IdP and help desk to Serval 2. Configure application and resource access for company-wide and team-specific resources 3. Define access policies with approval workflows and provisioning methods **Example: GitHub access configuration** Your IT team manages GitHub application access for the entire company. Your Engineering team controls access to specific repositories and teams. **Company-wide access** * **Name:** GitHub - Member * **Description:** Standard user access * **Policy:** Indefinite access, no approval required * **Provisioning:** Linked Group - add user to "Engineering" group in Okta **Team-specific access** * **Name:** GitHub Engineering Team - Administrator * **Description:** Full admin access to manage repos in GitHub Engineering Team * **Policy:** Seven-day temporary access, requires Engineering Manager approval * **Provisioning:** API provisioning through GitHub ## Best practices Leverage existing group structures and enable Linked Group provisioning Manage applications with the fewest teams possible for easier management and auditing Maintain consistency across roles with common access patterns Test each role configuration before rolling out to your organization Identify opportunities for automation and policy refinement ## **FAQs** Serval delivers Just-In-Time Privilege Access for databases, cloud roles, and application admin roles. Serval is adjacent to PAM but not a replacement for PAM's vaulting/session recording. **Access Profiles** determine who can request access (eligibility). **Access Policies** define the rules for those requests (approval requirements, duration limits, business justification). Think of profiles as "Can I ask?" and policies as "What do I need to provide?" No. Serval sits on top of your existing IdP (Okta, Azure AD, Google Workspace) and uses it for provisioning. Serval manages the access request workflow while your IdP continues handling authentication and group membership. It depends on the provisioning method: * **Direct provisioning:** Seconds * **Linked Groups:** 15 minutes to 1 hour, depending on your IdP's sync schedule * **Custom Workflows:** Varies based on workflow complexity * **Manual provisioning:** Depends on human response time Serval automatically revokes access using the same provisioning method. For Linked Groups, Serval removes the user from the IdP group. For Direct provisioning, Serval calls the API to revoke access. For Manual provisioning, Serval creates a removal task for the application owner. Yes. You might use Linked Groups for common member access, Direct provisioning for team-specific roles, and Manual provisioning for highly sensitive admin access—all within the same application. A **resource** is a grouping within an application (like a GitHub team or Slack channel). A **role** is the permission level within that resource (like Member, Admin, or Owner). Every app has a default "App Access" resource for baseline application access. While technically possible, it's not recommended. Managing individual channels or groups through Serval access management would require extensive manual configuration. These are better managed through custom workflows. For full audit trails of these resources, rely on your IdP logs. No. Start with high-value, high-frequency access requests. Common starting points include admin roles, temporary database access, and sensitive application access. You can always add more roles as adoption grows. Use Manual provisioning. Serval creates a task for the application owner to grant access manually. While not automated, this still centralizes the request and approval workflow and provides an audit trail. Yes, through Access Profiles. You can create multiple profiles for the same role with different eligibility criteria and approval requirements. For example, engineers might auto-approve for database access while contractors require manager approval. Yes. Users can request extensions to active access at any time, even while access is still being provisioned. Extension requests follow the same approval workflow as initial requests. Users can also shorten their access duration if they finish early. Yes. Approvers can approve requests for a different duration than what was requested. For example, if a user requests 2 hours of access, an approver can approve it for 30 minutes instead. This applies to both initial requests and extension requests. The amended request replaces the original pending request. If a user amends multiple times before approval, only the final amendment is what the approver sees. Earlier amendments are automatically superseded. Requests auto-approve with the requested duration. This also applies to extension requests. If you want all requests to require approval, make sure to configure at least one approver in your access policy. # Access Core Concepts Source: https://docs.serval.com/sections/access-management/configuration/access-concepts Core concepts for configuring access controls in Serval This guide explains the key concepts you'll use when setting up access management in Serval. *** ## Access Layers Understanding how Serval organizes access helps you configure it effectively. **Apps, Resources, and Roles** Serval organizes access in a three-level hierarchy: | Layer | What it means | Examples | | :- | :- | :- | | **Application** | The applications you connect to Serval. | GitHub, Slack, AWS, Okta, Linear | | **Resource** | Groupings within apps. Apps without subdivisions use a single "App Access" resource. | GitHub teams, Slack channels, AWS accounts | | **Role** | Access levels within resources. | Admin, Member, Viewer, Owner | Every app has a default resource called "App Access" that controls baseline access to the application itself. You can then create custom resources for finer-grained control. **Example:** In GitHub, "App Access" controls whether someone can use GitHub at all. A custom resource for the "Engineering" team controls who can access that specific team's repositories, with roles like "Member" or "Maintainer." ## **Profiles vs. Policies vs. Provisioning** Similar-sounding terms do different things: * [**Access Profiles**](https://docs.serval.com/sections/access-management/configuration/access-profiles) = Who can request access (eligibility) * [**Access Policies**](https://docs.serval.com/sections/access-management/configuration/access-policies) = Under what rules they can request it (approval, duration, justification) * [**Provisioning**](https://docs.serval.com/sections/access-management/configuration/access-provisioning) = How am I going to get the user into that particular role Think of profiles as the gate ("Can I even ask?") and policies as the rules once you're through the gate ("What do I need to provide?"). **Application Role Example**: A developer requests GitHub (application) --> Member (role) **Resource Role Example:** A developer requests GitHub (application) → Engineering Team repo (resource) → Write access (role) *** ## Role Configuration Access control in Serval uses three components that work together: Access Profile → Access Policy → Provisioning Method (Who can request) → (What rules apply) → (How access is granted and removed) When a user requests a role, Serval checks if they belong to a group in the Access Profile If eligible, the Access Policy determines duration, justification requirements, and approval workflow Once approved, the Provisioning Method actually grants the access (via IdP group, API, workflow, or manual task) Once the duration of access from the access policy has expired, the user is removed from role *** ## Quick Reference A **resource** is what you're accessing (e.g., the Engineering Team in GitHub). A **role** is the permission level within that resource (e.g., Write access to the Engineering Team). No. Simple applications can use just "App Access" as a single resource. Only create additional resources if you need to manage access to specific teams, channels, or subdivisions. Yes. Profiles and policies are designed to be reused. Create them once and apply them to multiple roles for consistency. You can update the provisioning method for a role at any time. This only affects future access requests. Existing access continues using the original method. # Access Policies Source: https://docs.serval.com/sections/access-management/configuration/access-policies Control access duration, justification requirements, and approval workflows Access policies define the rules that govern how users request and receive access to applications and resources. Create reusable policies to maintain consistent access controls across your organization. *** ## Understanding Access Policies When creating or editing an access policy, configure the following settings to manage duration, and approvals needed for roles. Descriptive name that indicates when the policy should be used (e.g., "High Security", "Standard Access") Detailed explanation of what the policy covers and when to apply it Maximum duration users can keep access before automatic revocation (options: indefinite, hours, days, weeks, months) Suggested duration to guide users toward shorter access periods while still allowing maximum if needed Toggle on to require users to explain why they need access; Serval evaluates reasonableness based on guidance settings Toggle on to add verification step when someone requests access for another user Select who must approve: specific users, groups (optionally with a quorum), the requester's manager, resource, app, or role owners, or a custom approval workflow Control whether approvers can approve their own requests, per approver or for the whole procedure Add sequential approval requirements where each step must be completed before the next begins How long each step waits for a decision before timing out (30 days by default). A step that times out ends the approval without granting access. View how many applications and roles will be affected by policy changes before saving Each step is governed by an **All must approve** or **Any one can approve** rule. For sequential approval, add multiple steps. Each step begins only after the previous one completes. Approvers can modify the requested duration when approving. For example, if a user requests 2 hours of access, an approver can approve for 30 minutes instead. This gives approvers flexibility to grant appropriate access based on the specific request context. For requests with staged approvals, Serval checks the approved duration against the current policy limit before accepting the approval for provisioning. If the duration exceeds that limit, the access request fails without granting access. The requester must submit a new request within the current limit. Access policy editor with duration, justification, and approval settings ### Approver justification Separately from the requester's business justification, an approval step can prompt the approver to record their own note when they decide a request. For each step, choose how the approver's note is handled: **None**, **Optional**, **Required**, **Required to approve**, or **Required to deny**. The approver enters the note as part of approving or denying, and it's captured wherever they act (Slack, Microsoft Teams, the Serval inbox, and the web ticket card) and stored with the decision. *** ## Create an Access Policy Click "Create policy" or select an existing access policy to modify Enter a policy name and description. Use descriptive names like "General Access" or "Temporary Admin Access" that indicate when the policy should be used. Choose indefinite or time-limited access for Max Access Length. Optionally set a Recommended Access Length to guide users toward shorter access periods while still allowing them to request the maximum if needed. Use time-limited access for elevated permissions like admin roles. Use indefinite access for standard user roles. Toggle on "Require business justification" to require users to explain why they need access. Serval will evaluate whether the justification is reasonable based on your guidance settings. Toggle on "Require confirmation for requests made on behalf of others" to add verification when someone requests access for another user. Build the procedure as a sequence of steps. In each step, add one or more approvers: specific users, groups (optionally with a quorum), the requester's manager, resource, app, or role owners, or a custom approval workflow. For each step, configure: * The approvers, and whether each is **notified** or a **backup** who can approve but isn't notified * Whether **all must approve** or **any one can approve** * For a group, a quorum: how many of its members must approve For the whole procedure, set whether approvers can self-approve their own requests (**Allow all approvers to self approve?**) and the **Approver justification** requirement (whether approvers must leave a note when they decide). Add multiple approval steps for sensitive access by clicking "Add approval step". Approvals happen sequentially—the second step only begins after the first is complete. Set **Approval timeout** to control how long each step waits for a decision before timing out, 30 days by default. If a step times out with no decision, the approval ends without granting access. Access policy approval steps with a step rule, an approver, and self-approval and justification settings Each step is governed by an **All must approve** or **Any one can approve** rule. For sequential approval, add multiple steps. Each step begins only after the previous one completes. Check how many roles will be affected by this policy before saving. Click "Save policy" to make it available for role configuration. You'll see which applications will be affected by the new policy. *** ## Manage Access Policies Once created, access policies can be managed centrally and applied to multiple roles across your organization. To access policy management, open the team in the sidebar, then go to **Settings** → **Access Policies**. Choose a default policy that applies to new roles automatically to ensure consistent baseline access controls. Modify policy settings. Changes apply to all roles using that policy, making it easy to update access controls organization-wide. See which roles currently use each policy to understand the impact before making changes. Add or remove roles that the policy should apply to. Reuse policies across similar access patterns for consistency. Set up new standard policies for your organization to be used across any number of roles. *** ## Best Practices Begin with tighter controls and loosen them based on feedback. It's easier to remove friction than add security later. Temporary access to admin or sensitive roles reduces security risk and ensures cleanup happens automatically. Create policies for access patterns, not individual roles. This makes management easier as you scale. Audit which policies are in use and whether they still match your security requirements. *** ## Extensions and Modifications Users can request extensions or reductions to their active access. These modification requests follow the same approval workflow as initial requests: * **Extensions require approval** if configured in the access policy * **Approvers can modify durations** when approving extension requests * **Users can amend requests** before approval (the final requested duration is what the approver sees) * **No approval required?** If no approval procedure is configured, requests and extensions auto-approve with the requested duration If a user amends their request multiple times before approval, only the final amendment is submitted for approval. Earlier amendments are automatically superseded. # Access Profiles Source: https://docs.serval.com/sections/access-management/configuration/access-profiles Define which users can request specific roles based on group membership Access profiles ensure only users in designated groups can request access to particular roles. This prevents unauthorized access requests and maintains security boundaries across your applications. *** ## Understanding Access Profiles Access profiles answer the question: "Who is allowed to request this role?" They work by mapping Serval groups to roles. When a user requests access, Serval checks whether they belong to a group that's allowed to request that role. A role can be linked to more than one access profile. A user who matches any linked profile can request the role, so linking additional profiles widens who is allowed to request it. **Example:** You can create an "Engineering" profile that only allows members of your engineering teams to request access to production databases. Configure the following settings to define which users can request specific roles: The user group identifier from Serval. Must match existing Serval group naming conventions. Optional context about the profile's purpose, target user population, or usage guidelines. Additional Serval groups included in this access profile. Use this to combine multiple groups under a single access policy. IdP groups linked to this profile. These determine which roles become requestable for users matching this profile. Match users by a user profile field. Built-in fields (Department, Job title, Email, Timezone, and Locale) are available alongside your custom fields. Pick a field, then choose the values that qualify (for example, everyone whose **Department** is Engineering). ## Profile Configurable in the Application Access profile configuration form with name, description, and group settings *** ## Create an Access Profile **Name:** The user group identifier from Serval. Must match existing Serval group naming conventions. **Description:** Optional context about the profile's purpose, target user population, or usage guidelines. **Associated Groups:** Additional Serval groups included in this access profile. Use this to combine multiple groups under a single access policy. For example, combine "Engineering-Frontend" and "Engineering-Backend" groups into a single "Engineering" profile. **Associated Roles:** IdP groups linked to this profile. These determine which roles become requestable for users matching this profile. Click "Save profile" to make it available for role configuration *** ## Manage Access Profiles Once created, access profiles can be managed centrally and applied to multiple roles across your organization. To access profile management, open the team in the sidebar, then go to **Settings** → **Access Profiles**. ### What You Can Do Choose a default profile that applies to new roles automatically. This is typically your broadest user group (e.g., "All Employees"). Modify profile settings. Changes apply to all roles using that profile, making it easy to update access permissions organization-wide. See which roles currently use each profile. This helps you understand the impact before making changes. Add or remove roles that the profile should apply to. Reuse profiles across similar access patterns for consistency. *** ## Profile Examples **Groups:** company-all-employees\ **Purpose:** Standard company-wide applications like Slack, Google Workspace **Use for:** Access that every employee should be able to request **Groups:** eng-frontend, eng-backend, eng-infrastructure\ **Purpose:** Engineering tools and production access **Use for:** Developer tools, code repositories, staging environments **Groups:** finance-accounting, finance-payroll\ **Purpose:** Financial systems and sensitive data **Use for:** Accounting software, payment processors, financial dashboards **Groups:** contractor-engineering, contractor-design\ **Purpose:** Limited access for external workers **Use for:** Non-sensitive tools and resources appropriate for contractors *** ## Best Practices Create profiles that mirror your actual organizational structure. This makes it intuitive for admins to assign the right profiles. Create an "All Employees" profile for widely-used applications. This reduces administrative overhead. Group teams with similar access needs together. For example, all engineering groups can share an "Engineering" profile. Write clear descriptions so admins understand when to use each profile when configuring new roles. *** ## Restricting workflows and skills Access profiles can also control who can request a [workflow](/sections/documentation/workflows/overview) and who a [help desk skill](/sections/documentation/skills/overview) applies to. With no profiles linked, a skill reaches every requester. To narrow it, link one or more access profiles to the skill from its editor: the skill then reaches only requesters who match a linked profile, using the same membership rules a profile uses to decide which roles it makes requestable. Linking more profiles widens the audience to anyone who matches any of them. *** ## Restricting knowledge bases Access profiles can also control who the help desk agent can surface a [knowledge base](/sections/documentation/knowledge-base/overview) to. Add a knowledge base to a profile, and the agent uses that base's content only for requesters who match the profile. Open the team in the sidebar, then go to **Settings** → **Access Profiles** and open the profile. Under **Knowledge Bases**, click **Add knowledge base** and select the base. The change applies when you add it. How a grant works: * **The grant restricts the base.** A knowledge base with no profiles is available to anyone in the org. When you add it to a profile, only requesters who match that profile get answers from it. * **More profiles widen the audience.** If you add the same base to several profiles, a requester who matches any of them gets answers from it. * **Pages and folders inherit the grant.** Everything in the base uses the base's profiles, unless a page or folder has its own **Visibility** setting. A page or folder with its own setting uses only its own profiles. * **It's the same setting as the base's visibility.** Adding a base to a profile here gives the same result as adding the profile in the knowledge base, under the base's actions menu → **Visibility**. You can see and change the grant from either place. * **It controls the help desk audience only.** Team roles still decide who can view and edit the base inside Serval. See [Access control](/sections/documentation/knowledge-base/authoring#access-control). Removing the last profile from a knowledge base makes the base available to anyone in the org again. To keep a base restricted while you change its audience, add the new profile before you remove the old one. You can't add a knowledge base whose permissions are synced from its connected source, such as ServiceNow. The picker shows it as **Access managed by source**, because the source decides who can see it. # Provisioning Methods Source: https://docs.serval.com/sections/access-management/configuration/access-provisioning Configure how access is granted to your applications and resources Provisioning methods determine how Serval grants access once a request is approved. Choose the method that best fits your technical setup and security requirements. *** ## Understanding Provisioning Method Selection ### The Four Provisioning Methods Serval offers four ways to grant access: | Method | How it works | Best for | Speed | | - | - | - | - | | **Linked Groups** | Adds user to IdP group; IdP syncs to app | Apps connected to your IdP with SCIM | Depends on IdP sync (minutes to hours) | | **Direct** | Serval calls app API directly | Apps with robust APIs, not in IdP | Seconds - configurable when importing a role | | **Custom Workflows** | Multi-step automation you build | Complex provisioning with dependencies | Varies by workflow | | **Manual** | Creates task for human to complete | Apps without automation options | Depends on human response | Provisioning method configuration showing Linked Groups, Custom Workflow, Direct, and Manual options ### Common Provisioning Scenarios **Best method:** Linked Groups **Why:** Simple app-level access, likely already using Okta or similar IdP for SSO **Setup:** 1. Create "App-Asana-Users" group in Okta 2. Configure Okta to provision Asana based on group membership 3. In Serval, link the "Member" role to this Okta group 4. When users request Asana access, Serval adds them to the group 5. Okta syncs the change to Asana (typically within 15 minutes) 6. When access expires, Serval removes them from the group **Best method:** Direct provisioning or Custom Workflow **Why:** GitHub teams are resources within GitHub, not separate apps **Setup with Direct:** 1. Create "Engineering" as a custom resource in Serval 2. Configure "Member" and "Maintainer" roles with direct provisioning 3. Serval uses GitHub API to add/remove users from the team 4. Access granted in seconds **Setup with Workflow (if you need approval notifications):** 1. Create workflow that calls GitHub API to add user 2. Send Slack notification to team lead 3. On expiration, call API to remove user **Best method:** Custom Workflow **Why:** Multi-step process with dependencies **Setup:** 1. User requests AWS access 2. Workflow creates Linear task: "Purchase AWS license" 3. Workflow opens GitHub PR to Terraform config 4. Workflow waits for Linear task completion 5. Auto-merge PR when task marked done 6. Apply Terraform to grant actual AWS access **Best method:** Manual Provisioning **Why:** No automation possible yet **Setup:** 1. Configure manual provisioning with clear instructions 2. Assign tasks to tool owner 3. Owner manually adds user in the tool 4. Owner marks task complete in Serval 5. For temporary access, Serval creates removal task when access expires **Plan to automate:** As request volume grows, consider building a custom workflow with the tool's database or building an API. ### Different Provisioning Strategies in a Single Application You can use different provisioning methods for different roles in the same application. **Example: GitHub** * **App-level "Member" access** → Linked Groups (via Okta) * **Team-specific "Maintainer" access** → Direct provisioning (via GitHub API) * **Organization "Owner" access** → Manual provisioning (too sensitive to automate) This approach balances automation for common requests with control for sensitive access. *** ## Linked Groups Access granted by adding the user to a group in your Identity Provider (Okta, Google, Rippling, Entra). When access expires, the user is automatically removed. ### How It Works User requests access and it's approved per the access policy Serval automatically adds the user to the specified IdP group Your IdP's existing rules provision the actual application access When access expires, Serval removes the user from the IdP group **Example:** Add the user to the "GitHub-Engineering" group in Okta. Okta's SCIM integration then grants GitHub access. After seven days, Serval removes the user from the group. ### Who Holds a Linked Role A role's linked groups also tell Serval who holds it: anyone who is a member of every linked group appears on the role's roster, whether Serval added them or they were already in the group when it synced. Removing the user from the group removes them from the role. When an access-review revocation or unused-license reclamation removes a role someone holds through linked groups, Serval removes them from those groups, whatever the role's provisioning method. The review's grant details show that the seat is held via linked groups and which groups confirm it. Linked groups can be configured on a role that uses any provisioning method. Turn off **Members of every linked group hold this role** on the role's Configure tab to make the links provisioning-only, so that only users granted the role through Serval count as members. Use this for bundle roles like an on-call role that provisions several admin roles at once. ### When to Use Linked Groups * Your IdP already provisions access via groups * You want automatic cleanup when access expires * You need audit trails in your IdP * You're managing access to multiple apps with one group * The application doesn't integrate with your IdP * You need more complex provisioning logic * Group membership would grant too much access *** ## Custom Workflow Access granted through a custom process—like using an API to send an email invite or opening a GitHub PR for a Terraform change. ### How It Works You define a workflow that Serval executes when access is granted. Workflows can include multiple steps, conditional logic, and integrations with various tools. Read more about how to set up [custom access workflows here](https://docs.serval.com/sections/access-management/configuration/custom-access-provisioning). ### Examples Add or remove users from a GitHub team that controls repository access. **Steps:** 1. Use GitHub API to add user to team 2. Send Slack notification to user and team lead 3. On expiration, remove user from team Open a GitHub PR for Terraform group membership, create a Linear task to purchase a license, auto-merge the PR when the task is complete. **Steps:** 1. Create Linear task: "Purchase AWS license for \[user]" 2. Open GitHub PR to add user to Terraform AWS group 3. Wait for Linear task completion 4. Auto-merge GitHub PR 5. Apply Terraform to grant actual AWS access Coordinate access across multiple systems during employee onboarding. **Steps:** 1. Create accounts in internal apps 2. Send welcome email with credentials 3. Add to Slack channels 4. Create onboarding tasks in project management tool 5. Schedule follow-up check-in with manager ### When to Use Custom Workflows * You need multi-step provisioning processes * Access requires API calls to multiple systems * You want to coordinate with other tools (Linear, GitHub, etc.) * Your provisioning logic has conditional branches * A simpler method (Linked Groups or Direct) would work * You're not comfortable building workflows * The process is entirely manual anyway *** ## Direct Provisioning Pre-built API provisioning for common applications. Serval uses the application's API to grant access directly. ### How It Works User requests access and it's approved per the access policy Serval makes an API call directly to the application to grant the specified role The user receives access within seconds, no manual intervention needed When access expires, Serval calls the API again to revoke access **Example:** When a user requests Ramp admin access, Serval automatically calls the Ramp API to grant the admin role. After the access period expires, Serval revokes it via the same API. ### Supported Applications Direct provisioning is available for select applications with robust APIs. ### When to Use Direct Provisioning * The application supports direct provisioning in Serval * You want fully automated provisioning without IdP groups * The application isn't connected to your IdP * You need immediate access grants * The application doesn't support direct provisioning yet * You prefer provisioning through IdP groups for consistency *** ## Manual Provisioning Access granted through a task assigned to the application owner (via ticket or Slack). A human manually grants the access. When you select a group configured as an [assignment group](/sections/documentation/ticketing/ticket-configuration/assignment-groups) for the task's team, that group owns the provisioning and removal tasks. The team's **Group member assignment** setting controls individual assignment: **Human triage** leaves the task with the group until someone claims it; **Round-robin** also assigns a group member. If you select multiple groups, the first group is the assignment target. To use group ownership, add the group through the team's assignment rules, default assignment, or **Ticket sidebar groups** before selecting it for manual provisioning. Other org groups continue to select an individual member. Instead of naming a user or group, you can leave the provisioner **Unassigned**. Serval then creates the provisioning task with no assignee, so it follows the team's normal ticket assignment rules. **Unassigned** and named assignees are mutually exclusive. ### How It Works User requests access and it's approved per the access policy Serval creates a task in your ticketing system or Slack assigned to the application owner The assigned person manually grants access in the application The owner marks the task complete in Serval If access is temporary, Serval creates another task to remove access when it expires **Example:** Jeff requests editor access to Linear. Serval creates a ticket assigned to the Linear admin. The admin adds Jeff as an editor and marks the task complete. For 12-hour temporary access, Serval creates a second task 12 hours later to remove Jeff's access. ### When to Use Manual Provisioning * The application has no API or IdP integration * Provisioning requires human judgment * The process is very infrequent * You're still building automation * You have high-volume access requests * Faster automated methods are available * Manual intervention creates bottlenecks *** ## Choosing the Right Method Use this decision tree to select the best provisioning method: **Yes** → Use **Linked Groups** * Most auditable approach * Works across multiple apps consistently * Best for apps your entire company uses **No** → Continue to next step **Yes** → Use **Direct Provisioning** * Fully automated * Access granted in seconds * No IdP dependency **No** → Continue to next step **Yes** → Use **Custom Workflow** * Most flexible option * Can coordinate across multiple systems * Handles complex approval chains * Requires workflow building skills **No** → Continue to next step Use **Manual Provisioning** when: * No automation options are available yet * Access requests are infrequent (\< 5 per month) * You're building automation but aren't ready yet **Important:** Document clear instructions for the person granting access. Plan to automate as request volume grows. ### Start Simple, Then Automate Don't feel pressure to automate everything immediately. A pragmatic approach: 1. **Week 1:** Set up manual provisioning for all apps to establish the request → approval flow 2. **Week 2:** Convert high-volume apps to Linked Groups or Direct provisioning 3. **Month 2:** Build custom workflows for complex provisioning scenarios 4. **Ongoing:** Automate manual processes as volume increases Manual provisioning today is better than delayed automation that never ships. *** ## Best Practices Use clear naming conventions for groups linked to Serval roles. Pattern: `App-[ApplicationName]-[RoleName]` Examples: `App-GitHub-Members`, `App-Asana-Admins`, `App-Figma-Editors` This makes it obvious which groups are managed by access requests and easier to audit. Start with Linked Groups or Direct Provisioning when possible. They scale better and reduce manual work. Linked Groups provide the best audit trail and work across multiple applications simultaneously. If you must use manual provisioning, write clear instructions for the person who will grant access. Start with manual provisioning if needed, but plan to build workflows or integrations as volume grows. The same method that provisions access must deprovision it. If you use a custom workflow to grant access, make sure it can also revoke access cleanly when time expires. Test the full lifecycle, not just the grant. # AWS Role Ingestion Source: https://docs.serval.com/sections/access-management/configuration/aws-role-access Serval can ingest AWS IAM roles from your linked accounts so they are visible in Serval (for example, for access reviews). Roles must be tagged for discovery, and Serval must be granted a policy that allows it to read role data. *** ## Ingestion Configuration Perform the following setup for *each* AWS account for which Serval will ingest roles. 1. Follow [the guide](/sections/integrations/aws) to add give Serval access to an AWS role in your account. 2. Once the role is created, navigate to permissions and select "Create inline policy" AWS IAM permissions tab with Create inline policy button 3. Add the following permission policy. These permissions are required to be able to properly ingest all the data we require: ```javascript theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:ListRoleTags", "iam:ListRoles", "iam:ListRolePolicies", "iam:ListAttachedRolePolicies", "iam:GetRolePolicy", "iam:GetPolicy", "iam:GetPolicyVersion", "iam:GetRole", "rds:DescribeDBInstances", "rds:DescribeDBClusters", "ec2:DescribeInstances", "eks:DescribeCluster", "eks:ListClusters" ], "Resource": "*" } ] } ``` ## Tagging roles for ingestion Serval only ingests roles tagged with the key `serval` (the value can be empty). Add this tag to each IAM role you want discovered during resource sync, and attach any AWS permission policies that define what the role can do. # Connect an IdP Source: https://docs.serval.com/sections/access-management/configuration/connect-idp Provision access through your Identity Provider and streamline user management Connecting your Identity Provider (IdP) to Serval enables automated access provisioning, leverages your existing group structure, and integrates with onboarding and offboarding workflows. *** ## What Is an IdP? An Identity Provider (IdP) is the central system that manages user identities and group memberships across your organization. Your IdP often serves as the single source of truth for who works at your company and which teams they belong to. **Common IdPs include:** * Okta * Microsoft Entra (formerly Azure AD) * Google Workspace * Rippling If you already use one of these systems to manage employee accounts and groups, you have an IdP. Connecting it to Serval unlocks powerful automation capabilities. *** ## Why Connect Your IdP to Serval Connecting your IdP transforms how you manage access by automating provisioning and leveraging your existing organizational structure. Serval provides just-in-time access by adding users to pre-existing IdP groups. ### Key benefits Grant and revoke access by adding or removing users from IdP groups—no manual work in individual applications Import all IdP groups to Serval and reuse them for access management without recreating your org structure Integrate with onboarding and offboarding to automatically provision or revoke access as employees join or leave ### How IdP integration improves access management **Manual and error-prone:** * Admin manually creates accounts in each application * Access must be granted individually per app * Offboarding requires tracking down every system * No centralized view of who has access where * High risk of forgotten access after employee leaves **Automated and auditable:** * Add user to an IdP group, access provisioned automatically * One group membership can grant access to multiple apps * Offboarding removes all access by removing from groups * Complete audit trail in both Serval and your IdP * Temporary access automatically expires and removes group membership *** ## Connect Your IdP Review the [integrations overview](https://serval-hannah-docs-custom-access.mintlify.app/sections/integrations/overview) to see supported IdP providers. If your IdP isn't listed, you can create a custom integration. Contact support for guidance on building custom IdP integrations. Each IdP has specific setup steps. Follow the integration guide for your provider to: * Create API credentials in your IdP * Grant necessary permissions to Serval * Configure the integration in Serval * Test the connection Configure SCIM (System for Cross-domain Identity Management) to automatically sync users and groups from your Identity Provider. After connecting, Serval imports all groups from your IdP as individual resources with the default role "Member" unless otherwise specified as "Admin." Large organizations with thousands of groups may take longer. Navigate to **Resources** to see all imported IdP groups. Each group appears as a resource you can use in access management. You can now provision access via Linked Groups when configuring roles. This automatically adds and removes users from IdP groups as access is granted and revoked. ## Using Your IdP in Access Management Once connected, your IdP integrates with Serval in several ways: ### Linked Group Provisioning The most common use case: provision access by adding users to IdP groups. **How it works:** When setting up a role, choose "Linked Groups" as the provisioning method Choose which IdP group should grant access to this role When a user requests and is approved for access, Serval adds them to the IdP group Your IdP's existing SCIM or provisioning rules grant the actual application access For temporary access, Serval removes the user from the group when access expires **Example:** Configure the "GitHub Engineering Team - Member" role to use the "GitHub-Engineering" Okta group. When users request access, they're added to the Okta group, which grants GitHub access via SCIM. After seven days, they're automatically removed. ### Importing Existing Role Configurations Serval analyzes your IdP groups to suggest role configurations you should import. **How it works:** 1. Serval identifies IdP groups that already provision access to applications 2. These appear in the import portal as suggested roles 3. You can import them with one click to start managing access via Serval 4. Existing group memberships are preserved Importing a role doesn't change who currently has access. It simply lets Serval manage future access requests using your existing IdP structure. ### Workflow Integration Use your IdP in custom workflows for complex provisioning scenarios. **Example workflows:** When a new employee is added to your IdP, trigger a workflow that: * Creates a ticket for IT setup * Adds to default company groups * Sends welcome email * Provisions standard tool access When someone changes teams (reflected in IdP), trigger a workflow that: * Removes old team access * Adds new team access * Notifies managers * Updates documentation When an employee is deactivated in your IdP, trigger a workflow that: * Lists all active access * Revokes all permissions * Creates audit report * Archives user data Periodically compare Serval access with IdP group membership to: * Identify access granted outside Serval * Flag orphaned group memberships * Generate compliance reports * Alert on discrepancies *** ## Managing IdP Groups in Serval ### Understanding Imported Groups When Serval imports your IdP groups, they appear as resources with special properties: **What gets imported:** * Group name * Group description * Current members * Nested groups (if applicable) **What doesn't change in your IdP:** * Existing group memberships remain unchanged * Your IdP's group structure stays intact * Users maintain current access Serval imports IdP groups as read-only snapshots. Changes you make in Serval (via access requests) sync back to your IdP, but Serval doesn't modify your IdP's group structure itself. ### Group Sync Behavior Serval keeps IdP groups in sync: * **Real-time for Linked Groups:** When Serval adds/removes users via Linked Group provisioning, changes happen immediately * **Periodic for group list:** The list of groups and their members syncs every hour to catch changes made directly in your IdP * **On-demand refresh:** You can manually trigger a sync from the IdP integration settings ### Special Cases: Groups to Exclude from Access Management Some IdP groups should not be managed through Serval's access management: Google groups used as access control lists (ACLs) for SSO don't grant application access—they only control who can authenticate. **These groups typically:** * Enable SAML SSO to applications * Don't grant specific permissions in the app * Follow naming patterns like "\[app]-sso-users" **Instead:** Manage the actual application access through Serval, not the SSO group. Email distribution lists are for communication, not access control. **Why to exclude:** * They don't grant application access * Adding/removing members doesn't affect permissions * They're managed by different teams **Instead:** Use dedicated access groups, not email lists, for provisioning. Some Okta groups grant automatic access to all employees (birthright access). **Special handling:** * These groups are imported but marked as "birthright" * Users don't request access—they're added automatically * Removing a user from these groups requires special approval **Instead:** Configure these as system-managed groups with restricted modification. Communication channel membership is typically managed within Slack/Teams, not through IdP groups. **Why to exclude:** * Channel membership doesn't map to IdP groups * Users join/leave channels frequently * Channel access is more social than security-critical **Instead:** Let users manage their own channel memberships in Slack/Teams. *** ## Best Practices Set up your IdP integration before configuring other applications. This lets you use Linked Groups from the start. Ensure your IdP groups have clear names that explain what access they grant. This makes role configuration easier. Don't recreate groups in Serval. Use your IdP's existing group structure for access management. Add descriptions to IdP groups explaining what access they grant. This helps when configuring Linked Groups. Regularly review who's in each IdP group. Serval can only provision access correctly if group memberships are accurate. If your IdP uses nested groups, understand how they work before configuring Linked Groups to avoid unintended access. *** ## Troubleshooting Common Issues **Possible causes:** * API permissions aren't sufficient * Connection to IdP is broken * Import is still in progress **Solutions:** * Verify API credentials have read access to groups * Check the integration status in Serval * Wait 5-10 minutes and refresh the page * Re-authenticate the integration if needed **Possible causes:** * Application doesn't integrate with your IdP * SCIM provisioning isn't configured * IdP provisioning rules are incorrect **Solutions:** * Verify the application supports SCIM from your IdP * Check your IdP's provisioning logs for errors * Confirm the IdP group is correctly mapped to the application * Test provisioning directly in your IdP first **Possible causes:** * Sync hasn't run in 24 hours * Manual changes were made in IdP after last sync * Sync failed silently **Solutions:** * Manually trigger a sync from integration settings * Check sync logs for errors * Verify API credentials are still valid * Wait a few minutes for sync to complete **Possible causes:** * Group was created after last sync * Group is excluded by sync filters * Group doesn't have any members **Solutions:** * Trigger a manual sync * Check if empty groups are excluded in integration settings * Verify the group exists in your IdP * Check for name changes in your IdP *** ## Security Considerations **Important:** Connecting your IdP to Serval grants API access to group memberships. Follow these security best practices: Create a dedicated service account in your IdP for Serval integration. Don't use a personal account. Only grant read access to groups and users. Serval only needs write access to modify group membership for provisioning. Turn on audit logging in your IdP to track all changes made by Serval's service account. Periodically review the API credentials and permissions to ensure they're still appropriate and secure. Serval encrypts all IdP credentials and uses them only to sync groups and modify memberships for provisioning. Your IdP credentials are never exposed to end users. # Custom Access Provisioning Source: https://docs.serval.com/sections/access-management/configuration/custom-access-provisioning Build custom workflows for resources that don't support SCIM provisioning Custom provisioning workflows automate access grants and revocations for resources without SCIM support. Define workflows using natural language instead of manual provisioning. Use SCIM provisioning when available. Custom workflows are for resources without SCIM support where you want to avoid manual provisioning. *** ## When to Use Custom Provisioning * The resource doesn't support SCIM * You have API or CLI access to the resource * Manual provisioning would otherwise be required ## How It Works Custom provisioning requires two workflows: * **Provisioning workflow:** Grants access * **Deprovisioning workflow:** Revokes access Both workflows must be explicitly defined. Workflows cannot reverse themselves. *** ## Create a Provisioning Workflow In Access Manager, open the role you want to configure Next to "Choose a provisioning workflow," click **+**, then select **Build a workflow** Catalyst opens with a prompt that identifies the application, resource, and role. Add any implementation details, then send the prompt. Continue describing the provisioning steps in natural language **Example:** Create a custom provisioning workflow with the following steps. 1. Check if the user has Slack user access 2. If the user lacks Slack user access, provision it first 3. Grant Slack admin access via API Click **Test workflow** to verify the logic Click **Publish** when ready Custom provisioning workflow builder interface showing natural language input *** ## Create a Deprovisioning Workflow In Access Manager, open the same role Next to "Choose a deprovisioning workflow," click **+**, then select **Build a workflow** Catalyst opens with a prompt that identifies the application, resource, and role. Add any implementation details, then send the prompt. Continue describing the deprovisioning steps in natural language **Example:** Create a custom deprovisioning workflow with the following steps. 1. Remove Slack admin access via API 2. Downgrade to Slack member access For applications where users likely have base access, only remove elevated access, not overall access. Test and publish the workflow *** ## Link Workflows to the Role In Access Manager, select the role Under "Custom workflow," select your published provisioning workflow Under "Deprovisioning workflow," select your published deprovisioning workflow The workflows are now active and will run automatically based on your access policy. Custom provisioning workflows execute only through access requests managed by the access policy. They cannot be triggered manually. View all provisioning and deprovisioning workflows in the Workflow Builder. Provisioning workflows are marked with a green key icon, deprovisioning with red. Workflow Builder showing provisioning and deprovisioning workflows with key icons *** ## Verify the Configuration Test the complete flow: 1. Submit an access request for the role 2. Verify the provisioning workflow executes correctly 3. Wait for the access period to expire or manually revoke access 4. Verify the deprovisioning workflow executes correctly # Access Management Overview Source: https://docs.serval.com/sections/access-management/overview Overview of Serval's Access Management solution Serval automates just-in-time (JIT) role-based access provisioning and deprovisioning directly from help desk requests. Serval manages the complete access request lifecycle - request, approval, provisioning, audit, and revocation - while integrating with your existing identity provider and applications. ## What Serval Manages Serval owns the access request workflow: who can request what, under which rules, how it's provisioned, and when it's automatically revoked. **Serval provides:** * Fine-grained access policies with time limits, approvals, and justification requirements that can be saved and reused across applications * Flexible provisioning via adding users to IdP groups, direct API, or custom AI-generated workflows * Real-time audit trails with attestation reminders, one-click revocation, and exportable logs for compliance * IdP integration to import existing roles, groups, and policies in minutes Serval integrates with your existing HRIS, identity provider, and identity governance systems to operationalize least-privilege role based access control on top of your existing infrastructure. ### The Complete Just-in-Time Access Lifecycle Serval manages access from request through automatic removal: 1. **Request** - User asks for access through the configured help desk (e.g., Slack, Teams, or app.serval.com) 2. **Eligibility check** - Access profiles determine if they can request this role 3. **Approval** - Access policies route the request to appropriate approvers (approvers can modify the requested duration) 4. **Provisioning** - Access is granted via your chosen method (linked group, direct API, custom workflows, or manual task) 5. **Active access** - User has access for the configured duration and can request extensions or reductions 6. **Automatic revocation** - When time expires, Serval removes access using the same provisioning method 7. **Logs** - Entire lifecycle is logged and accessible via Serval Users can modify their access at multiple stages: amend requests before approval, extend or shorten active access, and cancel pending requests. Approvers can also adjust durations when approving. ## How Access Management Works ### [For Administrators](https://docs.serval.com/sections/access-management/admin-quickstart) Connect your applications and configure role-based access control for any application role or resource role. [**Access Profiles**](https://docs.serval.com/sections/access-management/configuration/access-profiles) control which users can request access to specific applications, resources, or roles. Profiles determine eligibility before a request enters the approval workflow. [**Access Policies**](https://docs.serval.com/sections/access-management/configuration/access-policies) define the rules for each role, including time-bound access limits, approval requirements, and business justification requirements. [**Provisioning Methods**](https://docs.serval.com/sections/access-management/configuration/access-provisioning) determine how Serval grants access. Options include adding users to identity provider groups, direct API provisioning to applications, custom workflows, or manual provisioning tasks. [**User Access Reviews**](https://docs.serval.com/sections/access-management/access-reviews) let you certify that users still need their access. Scope who and what to review, assign reviewers to certify or deny each grant, and revoke what's no longer justified. UARs produce access-certification evidence for SOC 2, ISO 27001, and similar audits. [**Reclamations**](https://docs.serval.com/sections/access-management/reclamations) automatically reclaim access that people stop using. Sync last-login data, attach a reclamation policy to a role, then reclaim inactive grants (or let Serval auto-reclaim them) to remove unused standing access. ### [For End Users](https://docs.serval.com/sections/documentation/end-user/end-user-access) Most users don't know exactly which role they need. They know they need "Figma access" but not whether that's Editor, Admin, or Viewer access. Serval's conversational interface guides them to the right access level. Request access through two interfaces: **Conversational Interface:** Request access through Slack or Microsoft Teams. Serval helps determine which application and access level you need, routes approvals, provisions access, and automatically revokes access when the time limit expires. You can also extend, shorten, or cancel access through the same conversation. **Catalog:** Browse all requestable items from a single catalog in app.serval.com. Click **New Request** and select **Browse Catalog** to see two sections: * **Access** — Request role-based access to applications. The catalog surfaces details including descriptions and approval methods, so you can find the right access without guessing. Serval automates eligibility checks, approval routing, and provisioning. * **All Services** — Browse catalog items derived from workflows with form inputs. Select an item to create a ticket with the relevant form, making it easy to submit structured requests like new laptop orders, software installations, or onboarding tasks. Manage your active access, request extensions, or cancel pending requests from the access request card. **Extend access from any ticket:** Users can request additional time for expiring access from any ticket — not just the original request. Open a new ticket or revisit the original to extend access before it expires. ## Next Steps Admin Quickstart Guide Overview of access concepts End User Request Guide # Reclamations Source: https://docs.serval.com/sections/access-management/reclamations Automatically reclaim unused application access: sync last-login data, attach a reclamation policy to a role, then reclaim or dismiss inactive grants. *Reclamation* removes application access that people have stopped using, so unused access doesn't linger as standing risk. Serval tracks when each user last signed in to a connected app. When a grant sits unused past a threshold you set, Serval either reclaims the access automatically or routes it to a reviewer to decide. Every reclaim runs through the role's normal deprovisioning method and is logged. ## How reclamation works Reclamation runs on your access *grants* (one user holding one role) for roles that have a reclamation policy attached: 1. **Serval syncs last-login data** from the app, or from the identity provider that fronts it, so it knows when each user last signed in. Where you turn this on depends on how the role is provisioned (see [Step 1](#step-1-turn-on-last-login-sync)). 2. **A background sweep flags unused grants.** On a recurring schedule, Serval finds grants whose last login is older than the policy's inactivity threshold and turns each one into a *reclamation candidate*. 3. **The policy decides what happens next:** * **No reviewers on the policy**: the grant is reclaimed automatically (auto-reclaim). * **One or more reviewers on the policy**: the candidate goes to those reviewers, who reclaim or dismiss it. 4. **Reclaiming deprovisions the access** using the role's existing provisioning method and opens a reclamation ticket you can follow. **Dismissing** keeps the access and closes the candidate. Serval never removes access on its own unless the policy is set to auto-reclaim (no reviewers). With reviewers, nothing is deprovisioned until someone decides. ## Who can manage reclamation * Turning on **Last Login Sync** requires an organization admin. * Creating reclamation policies, attaching them to roles, and using the **Reclamations** page require the View Settings permission, which Managers and org admins have. See [Permissions](/sections/documentation/platform/permissions). Setting up reclamation is three steps: [sync last-login data](#step-1-turn-on-last-login-sync), [create and attach a reclamation policy](#step-2-create-and-attach-a-reclamation-policy), then [reclaim on the Reclamations page](#step-3-reclaim-on-the-reclamations-page). ## Step 1: Turn on last login sync Reclamation decides whether a grant is unused from each user's **last sign-in to the app the role is on**. Serval reads that sign-in from one of two places depending on how people reach the app, so turn last login sync on wherever the sign-ins actually live. Only organization admins can change these settings. Missing data never triggers a reclaim. If Serval has no last-login on record for a grant, the sweep skips that grant rather than treating it as inactive. ### Access provisioned through your identity provider (linked groups) When a role is provisioned with a **linked group** (for example, granting an app by adding the user to an Okta or Microsoft Entra ID group), people reach the app through your identity provider's single sign-on, and the app itself never reports the sign-in. Your IdP does. Turn on **Last Login Sync on the identity provider**, not on the downstream app. In the sidebar, open **Integrations**, select your **Okta** or **Microsoft Entra ID** connection, and open its **Settings**. Turn on the **Last Login Sync** toggle, then use **Sync now** to run it. One IdP sync imports each user's most recent sign-in to **every** app that IdP fronts, and Serval attributes each sign-in to the matching connected app, so all the roles behind that IdP become reclaimable from one place. For a downstream app's sign-ins to count, that app must be **connected in Serval** and matched to its entry in the identity provider (Serval links the two during app ingestion). Until an app is matched, its sign-ins are held aside and don't count toward reclamation, so connect the app before you rely on it. ### Access provisioned directly on the app When a role is provisioned **directly** on the app (its own API, a built-in workflow, or a manual task) rather than through an IdP group, the sign-in signal has to come from that app. Configure last login on **the app instance itself**. From **Integrations**, open the app and go to its **Settings**, then find the **Last Login Sync** section. If the app has a built-in importer, turn the **Last Login Sync** toggle on. If it doesn't, choose **Create workflow** (or **Attach an existing workflow**) and point a custom last-login ingestion workflow at wherever that app records sign-in activity. Use **Sync now** to confirm data flows. Built-in last-login importers exist only for **Okta** and **Microsoft Entra ID** today. Every other app either inherits sign-ins from the identity provider that fronts it (above) or needs a custom last-login ingestion workflow. Repeat for every app or identity provider whose access you want to reclaim. ## Step 2: Create and attach a reclamation policy A *reclamation policy* sets when unused access is reclaimed and who (if anyone) reviews it first. You attach a policy to a role to turn reclamation on for that role. A role with no policy attached is never reclaimed. ### Create a policy You can create a policy from **Settings → Reclamation Policies**, or inline while attaching one to a role (both open the same dialog). On the Reclamation Policies page, click **Create policy** and fill in: * **Policy Name** and **Policy Description**: a name and a short note about when to use this policy. * **Reclaim after (days of inactivity)**: the inactivity threshold. A grant becomes due for reclamation once its last login is older than this many days. Defaults to 90. * **Require a justification on each decision** (**Yes** / **No**): whether a reviewer must add a justification with every decision. * **Allow users to review their own access** (**Yes** / **No**): whether a reviewer can decide on their own grant. * **Reviewers**: the reviewer steps that decide on candidates before access is revoked. Reviewers control whether reclamation is automatic. If you add **no reviewers**, every license is reclaimed automatically once it passes the threshold. Add at least one reviewer step if you want a human decision before any access is removed. Click **Create policy** to save. You can edit or delete a policy later from the same page. A policy that's still attached to one or more roles can't be deleted until you detach it. If the policy has no reviewers, confirm **Create policy** in the warning dialog before it's created. Choose **Cancel** to return to the form. Select **Don't show this again** and confirm to skip this warning when creating or selecting any reclamation policy in this browser. Canceling doesn't save that preference. ### Attach a policy to a role From **Access → Manage Access**, open the application, select the role, and go to its **Configure** tab. In the **Reclamation Policy** section, open the policy selector and choose a policy, or leave it on **Off (no reclamation)** to keep reclamation disabled for this role. You can also pick **Create policy** here to make a new one without leaving the page. Once a policy is attached, the section shows a summary of its threshold and review steps. If the policy has no reviewers, confirm **Use policy** before it's selected. When creating a policy here with no reviewers, confirm **Create and use policy** to create and select it in one step. These warnings share the **Don't show this again** preference above. Save your changes to the role. Reclamation is now active for that role and its grants will be swept against the policy. ## Step 3: Reclaim on the Reclamations page Open **Access → Reclamations** to review candidates and act on them. The page has an **Overview** with candidate stats (candidates reclaimed, candidates dismissed, and your reclamation rate) and a **Reclamation candidates** table split into two tabs. ### In review The **In review** tab lists candidates awaiting your decision, one row per grant, with the **User**, the **Role**, and their **Last login**. For each row, choose: * **Reclaim**: deprovision the access. Serval revokes the grant using the role's provisioning method and opens a reclamation ticket. * **Dismiss**: keep the access and close the candidate. Select multiple rows to reclaim or dismiss them in bulk. Use the **All integrations** filter and the search box to narrow the list by app, resource, or role. If the policy requires a justification, you'll be asked for one before your decision is recorded. Reviewers are notified when they're assigned to a candidate, in their Serval inbox as well as Slack, Microsoft Teams, and email. ### Completed The **Completed** tab shows candidates that have been concluded, with a **Status** and who decided them under **Reviewed by**: * **Reclaiming**: deprovisioning is in progress. * **Reclaimed**: a reviewer reclaimed the access and deprovisioning finished. * **Auto-reclaimed**: the policy had no reviewers, so Serval reclaimed the grant automatically after the inactivity threshold. **Reviewed by** shows *System*. * **Dismissed**: a reviewer chose to keep the access. * **Failed**: deprovisioning didn't complete. Open the linked ticket to see what went wrong. From a reclaimed, in-progress, or failed status, you can open the **reclamation ticket** to see the full deprovisioning timeline (flagged as unused, deprovisioning queued, deprovisioning, and access reclaimed or reclaim failed). ## Related Certify access on a schedule for compliance, then revoke what's denied. Roles, access policies, and provisioning. # Deployment Checklist Source: https://docs.serval.com/sections/administration/deployment-checklist Step-by-step checklist for bringing Serval live in your organization, with links to the detailed setup guide for each area. # Deployment Checklist Use this page as your checklist for bringing Serval live in your organization. Work through the steps in order — each links to the detailed setup guide for that area. Have self-hosting requirements? Read the [Self-Hosting Options](/sections/self-hosting/index) page first. ## Go-live checklist Decide where employees reach Serval — [Slack](/sections/integrations/slack) (channels and [direct messages](/sections/documentation/helpdesk/interacting-with-serval-in-slack#direct-messages-dms)), [email](/sections/documentation/helpdesk/email), or [Microsoft Teams](/sections/integrations/microsoft-teams). A web portal is available automatically. See [Channels](/sections/documentation/helpdesk/channels#available-channels) for the full list. Employees can reach Serval through at least one channel. Connect your identity provider, communication tools, device management, and any existing ticketing or other systems you want Serval to work with. After connecting each app, open its **Settings → Sync History** to confirm syncs are completing cleanly. * [Browse integrations](/sections/integrations/overview) and review [Sync History](/sections/integrations/overview#integration-sync-history) * [Connect your identity provider](/sections/access-management/configuration/connect-idp) (Okta, Microsoft Entra, Google Workspace, Rippling) * Device management — Jamf, Iru, and Mosyle Each core integration shows recent, successful syncs. Set up the building blocks, then use them to route work: * [Categories](/sections/documentation/ticketing/ticket-configuration/categories), [labels](/sections/documentation/ticketing/ticket-configuration/labels), [priorities](/sections/documentation/ticketing/ticket-configuration/priorities), and [statuses](/sections/documentation/ticketing/ticket-configuration/statuses) * [Schedules](/sections/documentation/ticketing/ticket-configuration/schedules) and [SLAs](/sections/documentation/ticketing/ticket-configuration/slas) * [Assignment rules](/sections/documentation/ticketing/ticket-configuration/assignment#how-assignment-rules-work), built from the items above New tickets are categorized, prioritized, and routed automatically. Automate common requests. Install [pre-built workflows](/sections/documentation/workflows/Configure/installable#how-it-works) for your connected apps, or [build your own](/sections/documentation/workflows/create-your-first-workflow). Browse [examples by integration](/sections/documentation/workflows/Configure/installable#example-workflows-by-integration) for ideas. Your highest-impact requests have a workflow in place. Give the agent reference material to answer from: [connect a documentation source](/sections/documentation/knowledge-base/overview) (Notion, Confluence, Google Drive, SharePoint, ServiceNow, and more) or add a [custom ingestion workflow](/sections/documentation/knowledge-base/overview#path-2-use-a-custom-knowledge-ingestion-workflow). Knowledge is what the agent *knows*; [skills](/sections/documentation/skills-vs-knowledge) are how it *acts*. The agent can answer questions from your own content. Send representative requests through your front door and confirm routing, answers, and workflows behave. At a minimum, [submit a test ticket, verify user sync, and run a test automation](/sections/documentation/overview/day-1-setup#post-setup-verification). An end-to-end request works, from submission through resolution. ## Frequently asked questions This usually means a security proxy or WAF on your network is buffering or inspecting Serval's streaming responses, so the live part of a page never loads. See [Streaming pages behind a WAF or proxy](/sections/administration/network-security-and-firewalls#streaming-pages-behind-a-waf-or-proxy) for the fix. ## See also * [Day 1 setup](/sections/documentation/overview/day-1-setup) — the guided quickstart companion to this checklist. * [Self-Hosting Options](/sections/self-hosting/index) — choose a delivery model if you're running Serval yourself. # Network Security and Firewalls Source: https://docs.serval.com/sections/administration/network-security-and-firewalls Network configuration for running Serval on enterprise networks, including exempting Serval's streaming pages from proxy SSL/TLS inspection. # Network Security and Firewalls This page covers the network configuration for reaching Serval on enterprise networks: the Serval Cloud domains to allow through your firewall, and how to keep security proxies from breaking Serval's streaming pages. ## Serval Cloud domains Allow the following Serval Cloud (US) hosts so the web app and API work from your network. All Serval traffic is **HTTPS on port 443**; self-hosted deployments use your own domains instead. | Domain | Protocol | Port | Purpose | | - | - | - | - | | `app.serval.com` | HTTPS | 443 | Sign-in and landing page | | `.serval.com` | HTTPS | 443 | Your organization's web app, API, and streaming | | `api.us1.serval.com` | HTTPS | 443 | Shared API used during sign-in and org selection | | `svwebhook.us1.serval.com` | HTTPS | 443 | Inbound webhooks from connected apps | | `public.api.serval.com` | HTTPS | 443 | Public REST API (only if you use it) | **Wildcard alternative.** If your firewall accepts wildcards, allow `*.serval.com` and `*.us1.serval.com` (HTTPS, port 443). Note that `*.serval.com` does not match the two-label host `public.api.serval.com`, so allow that one explicitly if you use the public REST API. ## Streaming pages behind a WAF or proxy ### How Serval uses streaming Most web requests are simple round trips: the browser sends a request, the server returns one complete response, and the connection closes. Several Serval pages work differently. To show content that updates live — an AI reply forming as it is generated, a workflow run reporting progress, a ticket conversation updating in real time — they use a **streaming response**: a single HTTPS connection that stays open and delivers data progressively as it becomes available, rather than all at once at the end. This is the same idea behind live AI chat experiences across the web. It is normal, secure HTTPS traffic on port 443; the only thing unusual about it is that the response is long-lived rather than instantaneous. Pages that rely on streaming include the **workflow builder** and **workflow run** views and the **help desk ticket** view, along with other parts of the app that update live. Most other pages use ordinary requests and are unaffected. ### Why inspecting proxies break it Many enterprise networks route outbound traffic through a forward proxy, secure web gateway, or WAF — for example Zscaler or Cloudflare. To examine encrypted traffic, these devices typically perform **SSL/TLS inspection**: they decrypt the response, scan it (deep packet inspection), and re-encrypt it before passing it to the browser. Scanning generally requires the proxy to **buffer** the response until it is complete. A streaming response has no completion to wait for — it deliberately stays open. The proxy keeps buffering, waiting for an end that never comes, and nothing reaches the browser until the proxy's own timeout fires. The affected page appears to hang: the app loads, but the page never shows its live content and may eventually time out or error. ### Recognizing the problem An inspecting proxy is the likely cause when: * only specific pages are affected (workflow builder and runs, help desk tickets) while the rest of Serval works normally; * those pages sit on a loading state and never show live or AI-generated content; * the problem appears only on the corporate network or VPN, not when the same user is off-network; and * the behavior is consistent across users and browsers on that network. If pages fail everywhere — including off-network — the cause is more likely DNS, certificate trust, or general connectivity than a proxy. See [Private Network Access](/sections/self-hosting/private-network-access). ### Fixing it: exempt the Serval API from inspection **Serval Cloud** — your API host is region-specific, in the form `api..serval.com` (for example, `api.us1.serval.com`). You can confirm the exact host in your browser's developer tools, on the Network tab, while loading an affected page. See [Serval Cloud domains](#serval-cloud-domains) above for the full host list and wildcard options. **Self-hosted** — use the API hostname(s) for your deployment: either the per-service pattern `*.api.` or your unified API host `api.`, as configured during deployment. On your proxy or WAF, add a rule that exempts the Serval API hostnames from SSL/TLS inspection (also called HTTPS inspection or decryption). Match the exemption **by hostname, not by URL path**. Proxies evaluate this exemption against the hostname in the TLS handshake (the SNI) *before* they decrypt anything, so a hostname-scoped exemption leaves the streaming connection untouched end to end. Exempting from inspection also removes the response buffering and deep packet inspection that inspection performs — the behaviors that hold a streaming response open until it times out. The control is named differently by each vendor. Consult your vendor's documentation for the exact steps: Set the **Do Not Inspect** action on an SSL/TLS Inspection rule scoped to the Serval API hostnames. See [Skipping inspection of traffic to specific URLs or cloud apps](https://help.zscaler.com/zia/skipping-inspection-traffic-specific-urls-or-cloud-apps) (Zscaler docs). Create a **Do Not Inspect** HTTP policy for the hostnames. The HTTPS bypass matches on the TLS SNI and is evaluated before Allow/Block policies. See [TLS decryption](https://developers.cloudflare.com/cloudflare-one/traffic-policies/http-policies/tls-decryption/) (Cloudflare docs). Add an **SSL Decryption** policy with the **Do Not Decrypt** action for the hostnames. See [SSL decryption](https://docs.netskope.com/en/ssl-decryption/) (Netskope docs). Add the hostnames to **Decryption Exclusions** (wildcards allowed); the firewall matches on the TLS SNI and the server certificate common name. See [Decryption exclusions](https://docs.paloaltonetworks.com/network-security/decryption/administration/decryption-exclusions) (Palo Alto Networks docs). Add the hostnames to the **Web Selective Decryption List** so they pass through without decryption. See [Manage selective decryption](https://securitydocs.cisco.com/docs/umbrella-sig/olh/151445.dita) (Cisco docs). Other proxies (Fortinet, Forcepoint, Broadcom/Symantec, and similar) offer the same capability under names such as "SSL/TLS inspection exemption," "decryption exclusion," or "do not decrypt" — scope it to the Serval API hostnames. Reload an affected page — for example, open a help desk ticket or a workflow run. The live content appears and updates within a few seconds, on the corporate network, for all users. ### Self-hosted deployments If you run Serval yourself, the same constraint applies to any reverse proxy or load balancer you place in front of it: it must not buffer streaming responses (for nginx, set `proxy_buffering off` on the API routes). See [Self-Hosting Options](/sections/self-hosting/index) for delivery-model details. ## See also * [Private Network Access](/sections/self-hosting/private-network-access) — how Serval reaches systems on your internal network under each delivery model. * [Product security](/sections/documentation/platform/product-security) — Serval's security posture, data handling, and platform controls. # Troubleshooting Source: https://docs.serval.com/sections/administration/troubleshooting Triage common Serval issues, read integration Sync History, resolve permission problems, and gather what support needs. # Troubleshooting When something isn't working, start here. This page helps you triage the most common problems, check an integration's health, and — if you still need us — gather exactly what Serval support needs to help quickly. ## Common issues | Issue | Likely cause | Where to go | | - | - | - | | A page, or part of a page, is stuck loading | A WAF or proxy is buffering Serval's streaming responses | [Streaming pages behind a WAF or proxy](/sections/administration/network-security-and-firewalls#streaming-pages-behind-a-waf-or-proxy) | | An integration won't connect | The wrong user connected it, or admin consent is missing | [Common permission patterns](#common-permission-patterns) | | An integration's data is missing or out of date | A sync is failing | [Reading Sync History](#reading-sync-history) | | A workflow or action fails for one app | A missing permission for that action in the connected app | [Where did it break?](#where-did-it-break) | ## First five minutes Before escalating, these checks resolve most integration issues or pin down where the problem is: Open the integration's **Settings → Sync History** and look at the most recent run. A failed run shows an error message — note it. Run the integration's health check (named like **Test \[App] Connection**) to confirm Serval can still authenticate. For integrations that act as a specific user (for example, Slack Admin), confirm that account still has the required access in the connected app. Configuring or reconnecting an integration requires the **Team Manager** role. Note the exact error message and the timestamp — you'll need these if you contact support. ## Integration health and permissions ### Reading Sync History Each integration keeps a **Sync History** under its settings, showing recent sync runs. A healthy run shows a **Success** status and a breakdown of items **added, updated, and removed**. A failed run shows a **Failed** status with an error message. Serval doesn't categorize the failure for you, so read the message: * an **access or permission** error points to the connected account's permissions; * a **timeout or connection** error points to network, DNS, or firewall; * an **authentication** error points to expired or revoked credentials — [reconnect](#reconnecting-and-rotating-credentials) the integration. ### Where did it break? An integration failure is almost always at one of three points, and identifying which one saves time: 1. **Authentication** — Serval can't sign in to the app. Re-run its health check and look for an auth error. 2. **Data sync** — Serval is connected but can't read the expected data. Check Sync History. 3. **Actions** — Serval can read data but a specific action fails. This is usually a missing permission for that operation in the connected app. ### Common permission patterns Most integration problems trace back to a handful of setup issues: * **The wrong user connected the app.** Some integrations act with the connecting user's permissions. [Slack Admin](/sections/integrations/slack-admin) must be connected by an org owner or admin; [ServiceNow](/sections/integrations/servicenow) should use a dedicated service account, not a personal one. * **Missing Microsoft admin consent.** [Microsoft Graph](/sections/integrations/microsoft-graph), [Teams](/sections/integrations/microsoft-teams), and [Exchange Online](/sections/integrations/exchange-online) require an administrator to grant consent; without it, sign-in works but operations return access-denied. * **Google domain-wide delegation or org policy.** [Google Workspace](/sections/integrations/google-workspace) service-account access needs domain-wide delegation, and an org policy can block it ("Client is unauthorized…" or "Domain restricted sharing policy"). * **Wrong OAuth app type.** [ServiceNow](/sections/integrations/servicenow) needs an *inbound* OAuth app (client-credentials grant); the outbound / third-party options won't work. * **On-prem networking.** [LDAP / Active Directory](/sections/integrations/ldap-ad) needs firewall egress to the domain controller, DNS resolution, and — for LDAPS — a trusted CA certificate. ### Reconnecting and rotating credentials * **Reconnect** when an app's authorization has expired or its scopes changed — re-run its connect/authorization flow. * **Rotate** when you've changed an API key or secret in the connected system — update it in Serval so the two match. Both require the **Team Manager** role. ## Getting help from support ### What to send us To skip the back-and-forth, include: * your **organization name**; * **which integration**, and the account or app it's connected with; * the **error message and timestamp** from Sync History; * your **deployment model** — Serval Cloud, Hybrid, or self-hosted; * a **support token** (below), so we can investigate directly. ### Support tokens A **support token** lets Serval support securely access your environment for a limited time. From your profile menu, choose **Get support** and enable support access; the token expires automatically, and every support action is recorded in your Audit Logs. See [Support](/sections/documentation/platform/support#support-tokens) for details. ## See also * [Network Security and Firewalls](/sections/administration/network-security-and-firewalls) — fixes for streaming pages stuck behind a proxy. * [Integrations overview](/sections/integrations/overview) — connecting integrations and reading Sync History. * [Support](/sections/documentation/platform/support) — support tokens and contacting Serval. # Token types and permissions Source: https://docs.serval.com/sections/api-reference/authorization Understand which identity, scope, and permissions each API request needs. A valid token authenticates a caller. Each endpoint separately checks whether that caller can perform the requested action on the resource. Use [Find endpoints](/sections/api-reference/find-endpoints) to filter the API by your token type and permissions. ## Public API keys Exchange a public API key’s client ID and secret at [Create token](/api-reference/auth-api/create-token), then send the returned access token in the `Authorization: Bearer ...` header. * **Organization-scoped keys** can exercise their granted public API permissions across the organization. * **Team-scoped keys** have an `allowed_team_ids` restriction. Every team checked by the request must be on that allowlist. Organization-level and user-level checks fail even when the URL names an allowed team. * **Permission bundles** limit the actions a key can perform. Select the exact bundles granted to your key in the endpoint filter. A full-access key still has only the public API key permissions; it does not become a user token. The token exchange follows OAuth2’s client-credentials flow, but the resulting token still represents an API key. In the endpoint filter, select **API key**, not **OAuth**. ## User OAuth tokens A user-delegated OAuth token acts as the user who authorized it. The endpoint must accept user identities, and the user must have the required permissions through their roles and resource access. Accepting OAuth does not make an endpoint available to every signed-in user. Some endpoints, such as status updates, require a user token and are unavailable to public API keys even with full access. ## Request-specific checks An endpoint can support several request forms with different requirements. The filter includes an endpoint when at least one form matches your selection; each endpoint page explains its request-specific requirements. * Permissions joined by **+** are all required. **Or** separates alternatives. * Publishing a workflow requires `workflows:deploy` as well as `workflows:write`. Saving a draft only needs the write permission. * Ticket archiving requires `tickets:archive`. Hard-delete requires `tickets:admin`; `tickets:write` grants neither. * Ticket and message searches without `team_ids` use an organization-level check. A team-scoped key must supply allowed team IDs. * Creating or listing approval delegations with an API key requires `delegator_user_id`. Omitting it selects the current user, and a key has no user identity. * Moving a ticket checks both the source and destination teams. One allowed team is insufficient. * Group ownership, entity sharing, ticket settings, and other resource rules can further restrict access. The filter describes authorization requirements. It does not validate a live token or guarantee that a request will succeed. Expired or revoked credentials, missing resources, invalid parameters, and resource-specific checks can still reject a request. # Cross App Access Source: https://docs.serval.com/sections/api-reference/cross-app-access Let your users access Serval from another app they're already signed into, without a second login Cross App Access (XAA) lets a user who is already authenticated in one of your apps obtain a Serval session without a separate Serval login — driven by an [ID-JAG (Identity Assertion JWT Authorization Grant)](https://datatracker.ietf.org/doc/draft-ietf-oauth-identity-chaining/) issued by your identity provider. This is how you integrate Serval with your own product's SSO so that, for example, an MCP agent running inside your platform can call Serval's public API as the current user, with no extra prompts. ## When to use XAA Use XAA when all of the following are true: * You already run an OIDC identity provider (Okta, Entra ID, Auth0, etc.) that can mint **ID-JAG** tokens via [RFC 8693 token exchange](https://datatracker.ietf.org/doc/html/rfc8693). * You have a user-facing app (SPA, native, or web) where users are already signed in. * You want a backend service you control to obtain a Serval access token on that user's behalf, without bouncing the user through a second browser login. If you just want to let users sign into Serval with OAuth from an AI tool, use the [MCP Server](/api-reference/mcp-server) — it's a turn-key OAuth flow. XAA is for the case where your own product is the OAuth client and you want the exchange to happen server-to-server. ## How it works ``` ┌─────────────┐ │ Browser │ │ (User) │ └──────┬──────┘ │ 1. Sign in ▼ ┌─────────────┐ │ Your SPA │ │ (public) │ └──────┬──────┘ │ 2. Pass user token ▼ ┌─────────────┐ ┌─────────────┐ │ Your BFF │───────────────▶│ Okta │ │(confidential)│ 3. Token │ (Org AS) │ └──────┬──────┘ exchange └──────┬──────┘ │ │ │◀─────────────────────────────┘ │ 4. ID-JAG (signed JWT) │ │ 5. POST /oauth/token with ID-JAG ▼ ┌─────────────┐ │ Serval │ → access_token, scope └─────────────┘ ``` 1. The user authenticates in your SPA through your identity provider. 2. Your SPA hands the user's `id_token` (or access token) to a backend service you control — the **BFF**. 3. The BFF calls your IdP's token endpoint with `grant_type=urn:ietf:params:oauth:grant-type:token-exchange`, authenticating as the BFF's confidential client. It asks for an ID-JAG audienced to Serval's resource app. 4. The IdP validates the user's session, validates the cross-app-access grant, and mints an ID-JAG JWT. 5. The BFF forwards the ID-JAG to Serval's token endpoint (`/oauth/token`) along with Serval-issued **XAA client credentials**. Serval validates the JWT, resolves it to a user, and returns an access token. The BFF can then use that access token to call the [Serval public API](/api-reference/auth-api/create-token) or the [MCP Server](/api-reference/mcp-server) on behalf of the user. **Why do you need a BFF?** Token exchange at Okta (and equivalent IdPs) requires a confidential client — one that can authenticate with a client secret. SPAs are public clients and cannot hold secrets, so a small server-side component must perform the exchange hop. Same reason the industry converged on the BFF pattern for browser-based OAuth. ## Setup checklist You need two Okta (or equivalent) apps: * **Source app** — the app your users sign into. Usually an existing SPA or web app. * **Resource app** — a separate Okta app that represents Serval. Its `client_id` becomes the `audience` on every ID-JAG and must match what you register with Serval. Enable **Cross App Access** on your Okta tenant if it isn't on already (this is a tenant-level feature flag; on trial orgs it may require opening a support case). On the source app: * Add **Token Exchange** (`urn:ietf:params:oauth:grant-type:token-exchange`) to the list of allowed grant types. * Under the Cross App Access tab, add the resource app as an allowed target. * Ensure **Client authentication** is `client_secret_basic`, `client_secret_post`, or `private_key_jwt` — SPAs (auth method `None`) cannot perform token exchange; register a confidential Web app for the BFF. On **both** apps: * Assign your test user (and eventually all users who should get Serval access). * Ensure tokens are minted by **Org AS** (issuer `https://{your-tenant}.okta.com`), not by a custom authorization server at `/oauth2/default`. Serval validates the issuer on the assertion against the registered trusted IdP — the two must match exactly. As a Serval org admin, go to **Admin Settings → Security → Cross-App Access** and click **Add Identity Provider**. Fill in: * **Issuer URL** — your IdP's OIDC issuer URL (e.g. `https://acme.okta.com`). Must exactly match the `iss` claim on your ID-JAGs. * **Audience (Client ID)** — your **resource app**'s client ID (e.g. `0oa123t13csF7xmhC698`). Must exactly match the `aud` claim. * **Subject claim** — `sub` (recommended; works with opaque Okta `00u...` identifiers) or `email`. Serval discovers the JWKS URI from the issuer's `.well-known/openid-configuration`, so the issuer must be publicly reachable over HTTPS. You can also use the API directly: ```bash theme={null} curl -sv https://your-serval-host/svauth.user.SvUserAuthService/CreateTrustedIdP \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "issuer": "https://acme.okta.com", "audience": "0oa123t13csF7xmhC698", "subjectClaim": "sub" }' ``` The XAA client is the OAuth client your BFF authenticates as when calling Serval's token endpoint. Each one is scoped to a single trusted IdP. In the admin UI, expand the identity provider you just created and click **Add Client**. Fill in: * **Client ID** — the **client\_id** that your IdP will put on the `client_id` claim of ID-JAGs. For Okta, this is the **client ID of the source app** (not the resource). * **Display Name** — a human-readable label for this client (e.g. "Acme BFF"). The dialog returns a **client secret in plaintext exactly once**. Copy it immediately and store it somewhere only your BFF can read. Serval persists only a bcrypt hash; you cannot retrieve the secret later — only rotate by creating a new XAA client and revoking the old one. You can also use the API directly: ```bash theme={null} curl -sv https://your-serval-host/svauth.user.SvUserAuthService/CreateXAAClient \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "trustedIdpId": "", "displayName": "Acme BFF", "clientId": "0oa123t9nd2dv0Uqs698" }' ``` With the Okta source-app credentials (used to call Okta's token endpoint) and the Serval XAA client credentials (used to call Serval's token endpoint), your BFF can now perform the full exchange. Once you install and connect Okta in Serval, the user sync populates Serval's internal `external_users` table automatically — mapping each Okta user's `sub` to a Serval user in the same org. ID-JAGs carrying only a `sub` (no `email`) then resolve correctly. No per-user action is required. If you configure XAA before the first user sync completes, ExchangeIDJAG will return `PermissionDenied` on any exchange until the sync runs once. ## Exchange flow in detail ### Step 1 — Obtain an ID-JAG from your IdP Your BFF performs RFC 8693 token exchange against your identity provider. For Okta: ```bash theme={null} curl -sv https://acme.okta.com/oauth2/v1/token \ -u "$OKTA_SOURCE_CLIENT_ID:$OKTA_SOURCE_CLIENT_SECRET" \ -d grant_type=urn:ietf:params:oauth:grant-type:token-exchange \ -d "subject_token=$USER_ID_TOKEN" \ -d subject_token_type=urn:ietf:params:oauth:token-type:id_token \ -d requested_token_type=urn:ietf:params:oauth:token-type:id-jag \ -d "audience=$OKTA_RESOURCE_CLIENT_ID" \ -d scope=serval:user ``` * `subject_token` — the current user's `id_token` (or access token) from your SPA. * `audience` — the client ID of the Serval **resource** app. * `scope` — must be exactly `serval:user`. Other values are rejected by Serval. On success, the response's `access_token` field contains the ID-JAG. ### Step 2 — Exchange the ID-JAG for a Serval access token Send the exchange to the public API of the region that hosts your organization: `https://public.api.serval.com` for US organizations, `https://public.eu1.serval.com` for EU organizations. The example below uses the US host. ```bash theme={null} curl -sv https://public.api.serval.com/oauth/token \ -u "$SERVAL_XAA_CLIENT_ID:$SERVAL_XAA_CLIENT_SECRET" \ -d grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer \ --data-urlencode "assertion=$ID_JAG" ``` * `grant_type` — the OAuth 2.0 JWT Bearer grant type ([RFC 7523](https://datatracker.ietf.org/doc/html/rfc7523#section-2.1)). * `assertion` — the ID-JAG from step 1. * `-u` — HTTP Basic authentication with the XAA client credentials from setup step 3. A successful response looks like: ```json theme={null} { "access_token": "eyJhbGci...", "token_type": "Bearer", "expires_in": 3600, "scope": "serval:user" } ``` Use the `access_token` as a Bearer credential when calling the Serval public API or the MCP server. The response intentionally omits a refresh token — XAA tokens are short-lived, and renewal is driven by repeating the exchange. ## ID-JAG requirements Serval validates every ID-JAG against the strict shape below. Any deviation returns `invalid_grant` from `/oauth/token` and surfaces in the `error_description` field. ### Header | Field | Required value | | - | - | | `alg` | Any asymmetric algorithm your IdP's JWKS advertises. Must match the key. | | `kid` | Key ID matching an entry in the IdP's JWKS. | | `typ` | Exactly `oauth-id-jag+jwt`. | ### Claims | Claim | Requirement | | - | - | | `iss` | Must match the `issuer` registered in your trusted IdP. | | `aud` | Must match the `audience` registered in your trusted IdP (the resource app's client ID). | | `sub` | Required. The opaque user identifier from your IdP (e.g. Okta's `00u...`). Used to resolve a Serval user via the auto-populated `external_users` table. | | `exp` | Required. Serval enforces a 60-second leeway. | | `iat` | Required. Cannot be more than 60 seconds in the future. | | `jti` | Required. Used for replay protection — any `(iss, jti)` combination is accepted at most once. | | `client_id` | Required. Must equal the `client_id` of the XAA client you registered with Serval. | | `scope` | Must be exactly `serval:user`. Space-separated lists with additional scopes are rejected. | | `aud_sub` | *Optional.* When present and valid UUID format, Serval prefers resolving the user by this Serval user ID directly and falls back to `sub`-based resolution on mismatch. Useful if your IdP stores the Serval user ID alongside the Okta user. | | `resource`, `authorization_details` | Not supported. Send `null` or omit. Non-null values are rejected. | ## The MCP use case The most common reason to use XAA is giving an MCP agent running inside your product access to Serval on behalf of the current user. The flow is identical to the above — your product's BFF obtains a Serval `access_token` via XAA, then hands it to the MCP client as a Bearer credential instead of using the browser-based OAuth flow: ```json theme={null} { "mcpServers": { "serval": { "url": "https://public.api.serval.com/mcp/", "headers": { "Authorization": "Bearer ${SERVAL_ACCESS_TOKEN}" } } } } ``` EU organizations use `https://public.eu1.serval.com/mcp/` as the server URL. Repeat the XAA exchange before the token expires (check `expires_in` in the token response). ## Troubleshooting Your BFF's XAA client credentials are wrong, the XAA client has been revoked, or the authenticated client isn't linked to the trusted IdP that issued the assertion. * Confirm you're using the **Serval XAA client secret**, not your Okta source app's secret. * Re-check that the XAA client appears under the correct identity provider in **Admin Settings → Security → Cross-App Access**. The client must be scoped to the trusted IdP whose `iss` appears on the assertion. * If you rotated credentials by creating a new client, ensure your BFF picked up the new secret. The assertion's shape doesn't match what the trusted IdP row expects. Common causes: * `iss` mismatch — your IdP issued the token through a custom Authorization Server (`.../oauth2/default`) instead of Org AS. Reconfigure to use Org AS or change the trusted IdP's `issuer`. * `aud` mismatch — the assertion is audienced to a different client than what you registered. * Expired or not-yet-valid — check `exp`/`iat`; Serval enforces 60s leeway. * Missing `typ: oauth-id-jag+jwt` header — your IdP isn't minting an ID-JAG (it might be issuing a plain id\_token or access\_token). Confirm the token exchange requests `requested_token_type=urn:ietf:params:oauth:token-type:id-jag`. * Missing `jti`, `client_id`, or `iat` — required by Serval. * `scope` isn't exactly `serval:user`. The Okta user hasn't been synced to Serval yet, or the sync hasn't populated the mapping for this user. * Verify the Okta integration is installed in your Serval workspace and a user sync has completed successfully. * Confirm the user is assigned to both the source Okta app and the resource Okta app. * The mapping is populated on the sync cycle **after** a user's Serval account is materialized. For brand-new users, wait one sync interval and retry. ID-JAGs are single-use per `(issuer, jti)`. If your BFF retried the exchange call or cached the same assertion, Serval will reject the replay. Get a fresh ID-JAG from Okta and try again. This error is not retriable with the same assertion. This error comes from Okta, not Serval. Your source app doesn't have the token-exchange grant enabled. Open the app in Okta Admin → General → Grant types and add `urn:ietf:params:oauth:grant-type:token-exchange`. If the checkbox is absent, Cross App Access isn't enabled on the tenant. ## Security notes * **Rotate XAA client secrets** the same way you rotate any OAuth credential. Create a new API client from **Admin Settings → Security → Cross-App Access** (or call `CreateXAAClient` via the API), update your BFF with the new secret, then revoke the old client from the same UI (or call `RevokeXAAClient`). * **Tenant isolation.** Each ID-JAG issuer is globally unique in Serval — you cannot register the same `iss` on two organizations. This prevents an assertion from organization A from resolving to a user in organization B. * **Replay protection.** Serval records every accepted `(iss, jti)` tuple and rejects reuse. Your IdP must include a unique `jti` on every assertion (Okta does by default). * **Short-lived tokens.** Serval access tokens obtained via XAA expire quickly. Design your BFF to repeat the exchange on demand rather than caching long-lived credentials. * **Do not forward raw ID-JAGs to untrusted clients.** An ID-JAG is as sensitive as a password — anyone holding one before its `exp` can mint a Serval session for that user. Keep the token inside your BFF. # Find endpoints Source: https://docs.serval.com/sections/api-reference/find-endpoints Find API endpoints that support your token type, key scope, and permissions. Choose the kind of token you use. For API keys, choose organization or team scope and the permissions granted to the key. The filters narrow the existing API groups and endpoint links in the navigation. Your selection stays active as you browse endpoint pages in this tab. Use **Show all endpoints** to restore the full navigation. No token or secret is needed here. # MCP Server Source: https://docs.serval.com/sections/api-reference/mcp-server Connect AI agents and tools to Serval using the Model Context Protocol Serval exposes its entire public API as an [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server, allowing AI agents and LLM-powered tools to interact with your Serval workspace programmatically. Every public API endpoint is automatically available as an MCP tool. ## Base URL Each Serval region runs its own MCP server. Use the URL for the region that hosts your organization: | Region | Application URL | MCP server URL | | - | - | - | | United States | `https://app.serval.com` | `https://public.api.serval.com/mcp/` | | European Union | `https://app.eu1.serval.com` | `https://public.eu1.serval.com/mcp/` | The OAuth approval step opens the web app of the region that owns the server URL. An EU organization configured with the US server URL is sent to `app.serval.com`, where its users cannot sign in. See [Data residency](/sections/documentation/platform/data-residency). The examples below use the US server URL. EU organizations replace it with `https://public.eu1.serval.com/mcp/`. The server implements the [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http) defined by the MCP specification. ## Authentication The MCP server uses [OAuth 2.1](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization). Your MCP client handles authentication automatically — you provide the server URL, the client discovers OAuth endpoints, opens your browser for approval, and manages tokens. No credentials to copy or rotate. 1. Configure your MCP client with your region's server URL (for example `https://public.api.serval.com/mcp/`). 2. When the client connects, it will open your browser to approve access to your Serval workspace. 3. After approval, the client receives tokens and refreshes them automatically. ## Client Configuration Add the following to your `.cursor/mcp.json` file: ```json theme={null} { "mcpServers": { "serval": { "url": "https://public.api.serval.com/mcp/" } } } ``` When you first connect, Cursor will open your browser to approve access. Claude Desktop requires a local bridge to connect to remote MCP servers. This setup uses [`mcp-remote`](https://www.npmjs.com/package/mcp-remote), which is installed automatically via `npx`. **Node.js v18+ is required.** Claude Desktop uses `npx` to run the bridge, which requires Node.js to be installed on your machine. If you don't have it, install it before proceeding: ```bash theme={null} # macOS (Homebrew) brew install node # Windows winget install OpenJS.NodeJS # Or download from https://nodejs.org/ ``` To verify Node.js is installed, run `which node && which npx` in your terminal — both should return a path. Add the following to your Claude Desktop configuration file (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%\Claude\claude_desktop_config.json` on Windows): ```json theme={null} { "mcpServers": { "serval": { "command": "npx", "args": ["-y", "mcp-remote", "https://public.api.serval.com/mcp/"] } } } ``` When you first connect, `mcp-remote` will open your browser to approve access. Tokens are cached locally and refreshed automatically. **"Failed to spawn process: No such file or directory"** Claude Desktop cannot find `npx` or `node`. This usually means Node.js is not installed, or it was installed via a version manager (nvm, fnm, volta) that is not visible to Claude Desktop. Install Node.js globally using one of the methods above, then restart Claude Desktop. **"Server disconnected" immediately after starting** Check the MCP logs for details. On macOS, run: ```bash theme={null} tail -n 50 ~/Library/Logs/Claude/mcp-server-serval.log ``` Common causes include an expired token or a network issue reaching `public.api.serval.com` (or `public.eu1.serval.com` for EU organizations). **The approval page opens on `app.serval.com`, but the organization is in the EU** The client is configured with the US server URL. Change it to `https://public.eu1.serval.com/mcp/` and connect again. Set the server URL to your region's MCP server URL (for example `https://public.api.serval.com/mcp/`). The client will discover OAuth endpoints automatically and handle the browser-based approval flow. For stdio-only clients, use [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) to bridge the connection: ```bash theme={null} npx -y mcp-remote https://public.api.serval.com/mcp/ ``` ## Available Tools Every endpoint in the [Serval public API](/api-reference/auth-api/create-token) is available as an MCP tool. Tool names, descriptions, and input schemas are derived directly from the API specification. Tools follow a consistent `snake_case` naming convention matching the API operation name. The tools most commonly used by employees connecting through an AI assistant: **Tickets** | Tool | Use case | | - | - | | `create_ticket` | "I need to submit a ticket" | | `get_ticket` · `search_tickets` | "What's the status of my ticket?" | | `list_ticket_messages` · `create_ticket_message` | "What did the agent say?" / "Let me add more details" | | `update_ticket` | "I want to close this" / "This is actually urgent" | | `list_statuses` · `list_priorities` · `list_labels` | Pick valid values when creating or updating | **Access requests** | Tool | Use case | | - | - | | `list_requestable_roles` · `create_access_request` · `list_access_requests` | "I need access to X" / "Did my access request get approved?" | **Workflows** | Tool | Use case | | - | - | | `list_workflows` | "What automations can I kick off?" | | `start_workflow_run` · `await_workflow_run_result` | "Run the onboarding workflow for me" | | `search_workflow_runs` · `get_workflow_run` · `list_workflow_run_tasks` | "What's the status of that provisioning request I triggered?" | **Identity** | Tool | Use case | | - | - | | `get_current_user` | Know who the employee is before acting | Use the MCP `tools/list` method to discover all available tools and their input schemas at runtime. Your MCP client handles this automatically. ## How It Works The MCP server translates each tool call into a REST API request: 1. Your AI agent calls an MCP tool (e.g., `list_tickets`) with the required arguments 2. The server maps the tool call to the corresponding REST endpoint (`GET /v2/tickets`) 3. Path parameters, query parameters, and request bodies are constructed from the tool arguments 4. The response is returned as the tool result The MCP server has the same capabilities, permissions, and rate limits as the REST API. Any action you can perform through the API, your AI agent can perform through MCP. ## Example Usage Here is an example of an AI agent using the Serval MCP server to list open tickets: ``` Agent: "Show me all open tickets" → Calls MCP tool: list_tickets Arguments: {} ← Returns: { "data": [ { "id": "abc-123", "title": "Cannot access VPN", "status": "OPEN", ... } ] } ``` ## Running Workflows AI agents can run Serval workflows directly through MCP. Workflow runs are asynchronous: starting a run returns immediately, and the agent waits for (or polls) the result. 1. **Find the workflow** with `list_workflows` (or `get_workflow` if the ID is known). 2. **Start the run** with `start_workflow_run`, passing the `workflow_id` and any workflow arguments in `arguments` as a JSON object **encoded into a string** — not a raw JSON object (see the example below). The run starts on the workflow's currently-published version; pass `workflow_version_id` to pin a specific version. The response returns the run immediately with a `pending` or `running` status. 3. **Wait for the result** with `await_workflow_run_result`, which blocks until the run reaches a terminal status or `wait_timeout_seconds` elapses (default 30s, capped at 60s). If the response has `timed_out: true`, call it again to keep waiting — or use `get_workflow_run` to poll. ``` Agent: "Request a new laptop for me" → Calls MCP tool: list_workflows ← Finds: "Laptop Request" (id: wf-456) → Calls MCP tool: start_workflow_run Arguments: { "workflow_id": "wf-456", "arguments": "{\"model\": \"MacBook Pro 14\"}" } ← Returns: { "data": { "id": "run-789", "status": "PENDING", ... } } → Calls MCP tool: await_workflow_run_result Arguments: { "id": "run-789" } ← Returns: { "data": { "id": "run-789", "status": "COMPLETED", ... }, "timed_out": false } ``` Runs execute under your identity and permissions, exactly as if you started the workflow in Serval. Starting a run requires the `run_published_workflow` permission (team contributor role or above), so users without it won't see the workflow-run tools in their tool list. Running an unpublished draft version instead requires `create_workflow_run` (team builder role or higher). Workflows with approval requirements still go through their normal approval process. The run stays in progress until approvers act, so long-running runs are expected. ## Pagination List endpoints return paginated results. Use the `page_token` parameter to retrieve subsequent pages: 1. Call the list tool without `page_token` to get the first page 2. If the response includes a `next_page_token`, pass it as `page_token` in the next call 3. Repeat until no `next_page_token` is returned ## Error Handling Tool calls that result in API errors return an error message with the HTTP status code and response body. Common errors include: | Status Code | Meaning | | - | - | | 401 | Invalid or expired access token | | 403 | Insufficient permissions for the requested action | | 404 | Resource not found | | 429 | Rate limit exceeded | # User profile fields Source: https://docs.serval.com/sections/api-reference/user-profile-fields Pin a field so ingestion stops overwriting it, and hand it back when you're done Nine user profile fields are **governed**: Serval tracks where each value came from and decides who is allowed to change it next. If a workflow sets a user's locale and the nightly directory sync keeps reverting it, this page explains why and how to make the value stick. The governed fields are `first_name`, `last_name`, `avatar_url`, `timezone`, `locale`, `department`, `job_title`, `manager`, and `primary_phone`. Email and role aren't governed by field pinning. `email` is ungoverned but not unprotected, because it is the address people log in with. Two rules apply to changing it on `PUT /v2/users/{id}`: * **If the user came from your directory, change their email in your identity provider.** Serval rejects the write rather than let the next sync silently revert it. * **Two users in one organization cannot share an address, and deactivating a user does not release theirs.** If the address you want is already taken, the error names the user holding it. Move that user to another address first, then retry. * **Change email by itself.** A rename crosses the user database and login system, so Serval rejects requests that combine it with other profile changes. * **A user who belongs to multiple organizations can't be renamed through this endpoint.** Login identity is global, while the API caller is scoped to one organization. Connected user syncs can rename users too. When the highest-ranked source with user syncing on (Okta or Google Workspace, ahead of Slack and the rest) reports a new address for a synced user, Serval moves that user to it and keeps the login system in step, the same way a SCIM directory does. If the new address already belongs to another user in the organization, Serval leaves both accounts as they are and records the conflict instead of merging them. Contact Serval to enable sync-driven renames for your organization. You pin `department` and `job_title` the same way as `locale`: list `USER_PROFILE_FIELD_DEPARTMENT` or `USER_PROFILE_FIELD_JOB_TITLE` in `pinFields`. Any `department` value you save joins the org's set of department options automatically. ## Who wins Three classes of writer compete for a governed field. The highest-ranked writer that has touched the field owns it. | Rank | Writer | How a value gets here | | :- | :- | :- | | 1 | **Directory sync** | Your IdP, through SCIM or directory sync. Locks the field against everyone else, including you. | | 2 | **Pinned deliberate edit** | A person editing in the Serval UI, or an API call that pinned the field. Blocks automation. | | 3 | **Automation** | User ingestion, connected apps, and unpinned API calls. | A pin protects a field from automation. It doesn't protect it from directory sync: if your IdP supplies a value, change it in the IdP. ## Pinning depends on your token Whether a write pins by default depends on how you authenticated: * **User token**: pins by default. A person editing their own profile owns that value. * **API key or worker token**: doesn't pin. Your write stays automation-class unless you ask for a pin explicitly. That default is why a workflow's edits get overwritten: an API key writing `locale` looks identical to ingestion writing `locale`, so the next sync is free to replace it. ## Pin a field List the field in `pinFields` on `PUT /v2/users/{id}`: ```json theme={null} { "locale": "fr-FR", "pinFields": ["USER_PROFILE_FIELD_LOCALE"] } ``` The field is now pinned. Ingestion and connected apps can no longer change it, and it stays pinned until you release it or a later deliberate edit replaces it. A pinned field must be **set in the same request**. You can't pin a value that's already stored. Send the value and the pin together, so the request's outcome doesn't depend on state you can't see. Two fields are special: * **`avatar_url` can't be pinned.** Avatars live under a predictable key that automation can overwrite in place, so a pin wouldn't protect the image. Listing it returns `400`. * **`manager` pins through the relationship endpoints**, not here. See [Manager](#manager). An explicit pin replaces whatever pin was there before, including one a person set in the UI. Reach for it only when your workflow should own the field. You can also pin at creation time. `POST /v2/users` accepts `pinFields` for the two fields you can seed there, `first_name` and `last_name`: ```json theme={null} { "email": "ada@example.com", "firstName": "Ada", "pinFields": ["USER_PROFILE_FIELD_FIRST_NAME"] } ``` Without pins, the values you seed at creation stay open for ingestion to enrich. ## When your write doesn't land An API-key write to a field someone else owns doesn't fail. Serval applies the rest of the update and tells you what it skipped: ```json theme={null} { "data": { "...": "the updated user" }, "skippedPinnedFields": ["USER_PROFILE_FIELD_FIRST_NAME"], "skippedDirectoryLockedFields": ["USER_PROFILE_FIELD_LAST_NAME"] } ``` The response is still `200`. Check these two arrays if your workflow depends on the write landing. * `skippedPinnedFields`: a person, or another deliberate edit, owns this field. Send `pinFields` to take ownership. * `skippedDirectoryLockedFields`: your IdP supplies this field. Change it there. No API call can take it. Two details worth knowing: * If you write the value a pin already holds, the request succeeds cleanly and the field isn't reported as skipped. Re-asserting the current state is a no-op, not a conflict. * A directory-locked field is **always** reported, even when your value matches. Serval checks the lock before comparing values. User tokens behave differently. A user-token write replaces pins without complaint, but a write to a directory-locked field fails the entire request with `400` rather than skipping the field. ## Release a field Releasing hands a field back to automation. The current value stays, but loses its protection, so the next sync may replace it. ```json theme={null} { "releaseFields": ["USER_PROFILE_FIELD_LOCALE"] } ``` Release works with both user tokens and API keys: if you can pin a field, you can hand it back. You can't set and release the same field in one request. ## Primary phone A phone number can belong to only one user in an organization. If connected-app ingestion supplies a primary phone that another user already owns, Serval skips that phone and publishes the remaining profile fields. The existing phone assignments stay unchanged. Direct phone edits still reject duplicate assignments. The skipped value remains in the source data. Resolving the conflicting assignment alone doesn't retry an unchanged profile; the phone is reconsidered when the source profile changes or the user is explicitly republished. ## Manager `manager` is written through the relationship endpoints rather than `PUT /v2/users/{id}`, so its pin lives there too. Assign a manager with `POST /v2/user-relationships` and pin the assignment: ```json theme={null} { "userId": "", "relatedUserId": "", "relationshipType": "USER_RELATIONSHIP_TYPE_MANAGER", "pin": true } ``` Clear a manager with `DELETE /v2/user-relationships/{user_id}`, passing `pin` as a query parameter. Pinning a delete pins the *cleared* state, so ingestion can't re-assign the manager it thinks the user should have. The same token defaults apply: user tokens pin, API keys don't. Pass `pin: false` from a user token to assign a manager **without** taking ownership of the field. To hand the manager field back to ingestion, release it through `PUT /v2/users/{id}`: ```json theme={null} { "releaseFields": ["USER_PROFILE_FIELD_MANAGER"] } ``` ## What's next Full request and response schema, including `pinFields` and `releaseFields`. Assign a manager and pin the reporting line. Directory sync outranks every pin. Fields your IdP supplies are changed there. The equivalent model for Databases item types. # Webhooks Source: https://docs.serval.com/sections/api-reference/webhook Send webhook events from Serval workflows or trigger Serval workflows from external systems. Webhooks can move events in either direction. Choose the direction based on where the event starts: | Direction | Event starts in | Recommended approach | | - | - | - | | **Outbound** | Serval | Run a workflow that calls the destination's API | | **Inbound** | An external system | Create a webhook-triggered workflow in Serval | Serval does not provide a separate subscription system that pushes Serval events directly to arbitrary webhook URLs. Use a workflow for outbound webhook calls so you can control the trigger, payload, authentication, retries, and follow-up steps. ## Outbound webhooks: send events from Serval Use a workflow when a Serval event should notify an external system. The workflow determines when to send the notification and calls the destination through an existing integration or a [custom application](/sections/integrations/application). Use a catalog integration when one is available. Otherwise, connect a custom application with the destination's HTTPS API base URL and authentication. Custom applications support API keys, tokens, custom authentication headers, and OAuth 2.0 client credentials. Choose the workflow trigger that represents the event you care about, such as a Serval event, a schedule, or a help desk request. Add the integration's API action. For a custom application, use the **HTTP API request** action and specify the request method, endpoint path, parameters, and JSON body. Serval applies the configured base URL and injects the stored authentication at runtime. Test with a non-destructive endpoint or sandbox destination, confirm the receiving system accepts the payload, and then publish the workflow. You do not need a new custom application for every outbound webhook. Workflows can reuse the same connected application when the calls share a base URL and authentication. Create another application instance when a destination uses different credentials, a different API base URL, or a separate environment such as production and sandbox. Store API keys and client secrets in the integration setup, not in workflow code, inputs, or chat messages. Serval stores credentials encrypted and injects them server-side, so workflow authors do not need to handle the secret directly. ## Inbound webhooks: receive events in Serval Use a [webhook-triggered workflow](/sections/documentation/workflows/Configure/types#webhook-triggered-workflows) when an external system should start automation in Serval. Each published workflow receives a unique webhook URL and secret. Select **Webhook-triggered** as the workflow type, build the workflow steps that use the incoming payload, and publish the workflow. Open the trigger details and copy the unique webhook URL and webhook secret. Configure the external system to send an HTTP POST request to the webhook URL. Send a JSON body containing the values the workflow needs. Send the secret using `X-Webhook-Secret: YOUR_SECRET` (the default) or `Authorization: Bearer YOUR_SECRET`. The `secret` query parameter is supported for backward compatibility. Requests without a valid secret are rejected. Treat the webhook URL and secret as credentials. Anyone with a valid secret can trigger the workflow. You can rotate the secret without changing the URL; the previous secret remains valid for seven days unless you revoke it immediately. ## Which approach should I use? * **A Serval event should notify another system:** use an outbound workflow and call that system's API. * **Another system should start work in Serval:** use a webhook-triggered workflow. * **The destination already has a Serval integration:** prefer its typed workflow actions over a raw HTTP request. * **Several workflows call the same custom API:** reuse one connected custom application when its base URL and credentials are the same. # Access Requests Source: https://docs.serval.com/sections/cli/access Request, list, and cancel access to apps and resources using the Serval CLI # Access Requests The `serval access` command group lets you search available roles, submit access requests, view your existing requests, and cancel pending ones — all from the terminal. ## Commands | Command | Description | | - | - | | `serval access search [query]` | Browse roles available to request | | `serval access request` | Submit an access request | | `serval access list` | View your access requests | | `serval access cancel ` | Cancel or revoke an access request | *** ## serval access search Search the roles you are eligible to request access to. Without a query, all available roles are listed. With a query, results are filtered by team name, app name, resource name, or role name. ```bash theme={null} serval access search serval access search github serval access search "prod admin" ``` **Output columns** | Column | Description | | - | - | | `TEAM` | The team that owns this role | | `APP` | The application the role belongs to | | `RESOURCE` | The specific resource within the app (if applicable) | | `ROLE` | The display name of the role | | `ROLE ID` | The role ID used when submitting a request | *** ## serval access request Submit an access request for a specific role. The role ID can be found using `serval access search`. ```bash theme={null} serval access request --role-id serval access request --role-id --justification "Need read access for oncall investigation" serval access request --role-id --duration 480 ``` **Flags** | Flag | Description | | - | - | | `--role-id` | **(Required)** The ID of the role to request | | `--justification` | Business justification for the request | | `--duration` | Requested access duration in minutes. `0` means indefinite. Defaults to `0`. | **Duration validation** Before submitting, the CLI checks the role's access policy. If the role has a maximum allowed duration: * Requesting `--duration 0` (indefinite) will be rejected * Requesting a duration longer than the maximum will be rejected **Output** On success, the CLI prints the ticket reference and a direct link: ``` Access request submitted — ENG-42 https://app.serval.com/tickets/ENG-42 ``` *** ## serval access list List your access requests. By default, only active requests (pending approval or currently provisioned) are shown. ```bash theme={null} serval access list serval access list --all ``` **Flags** | Flag | Description | | - | - | | `--all` | Show full request history, not just active requests | **Status values** | Status | Meaning | | - | - | | `pending approval` | Waiting for an approver | | `provisioning` | Approved, access is being provisioned | | `active` | Access is currently granted | | `denied` | Request was denied | | `canceled` | You canceled the request | | `revoked` | Access was revoked | | `expired` | Access reached the end of its duration | | `failed` | Provisioning failed | *** ## serval access cancel Cancel a pending access request, or revoke an active one, by its request ID. Use `serval access list` to find the request ID. ```bash theme={null} serval access cancel ``` If provisioning has already started, the CLI automatically falls back to revoking the access instead of canceling it. # Installing the Serval CLI Source: https://docs.serval.com/sections/cli/installation How to install and update the Serval command-line interface # Installing the Serval CLI The Serval CLI is available for macOS, Linux, and Windows. We recommend using Homebrew for macOS users for the easiest installation and update experience. ## macOS (Homebrew) The recommended way to install the Serval CLI on macOS is through Homebrew: ### Install ```bash theme={null} brew install --cask servalhq/serval/serval ``` ### Update To update to the latest version: ```bash theme={null} brew update && brew install --cask servalhq/serval/serval ``` ## Manual Installation For other platforms or if you prefer manual installation: 1. Download the appropriate binary for your platform from the [releases page](https://github.com/ServalHQ/homebrew-serval/releases) 2. Extract the archive 3. Move the `serval` binary to a location in your PATH (e.g., `/usr/local/bin`) 4. Make it executable: `chmod +x serval` ### Linux Example ```bash theme={null} # Download the latest release (replace VERSION with actual version) wget https://github.com/ServalHQ/homebrew-serval/releases/download/VERSION/serval-linux-amd64.tar.gz # Extract tar -xzf serval-linux-amd64.tar.gz # Move to PATH sudo mv serval /usr/local/bin/ # Make executable chmod +x /usr/local/bin/serval ``` ### Windows 1. Download the Windows binary from the releases page 2. Extract the ZIP file 3. Add the directory containing `serval.exe` to your PATH environment variable 4. Or move `serval.exe` to a directory already in your PATH ## Verify Installation After installation, verify that the CLI is working: ```bash theme={null} serval version ``` This should display the installed version of the Serval CLI. ## Shell Completion The Serval CLI supports autocompletion for various shells. To enable it: ### Bash ```bash theme={null} serval completion bash > /etc/bash_completion.d/serval ``` ### Zsh ```bash theme={null} serval completion zsh > "${fpath[1]}/_serval" ``` ### Fish ```bash theme={null} serval completion fish > ~/.config/fish/completions/serval.fish ``` ### PowerShell ```powershell theme={null} serval completion powershell | Out-String | Invoke-Expression ``` # Serval CLI Overview Source: https://docs.serval.com/sections/cli/overview Command-line interface for managing Serval workflows, skills, and configuration # Serval CLI Overview The Serval CLI is a powerful command-line tool that enables you to manage your Serval workflows, skills, and configurations locally. With the CLI, you can pull workflows and skills from your Serval teams, edit them in your preferred development environment, and push changes back to Serval. The Serval CLI is currently in **beta**. While the core functionality is stable, some features and APIs may change as we continue to improve the tool based on user feedback. ## Key Features * **Pull and Push Workflows and Skills**: Download workflows and Help Desk and Catalyst skills from your Serval teams to edit locally and push changes back * **Version Control Integration**: Manage your workflows and skills in Git or other version control systems * **Team-based Organization**: Work with multiple teams and their respective workflows * **Secure Authentication**: OAuth-based device authentication flow ## Available Commands The Serval CLI provides the following commands: | Command | Description | | - | - | | `serval login` | Authenticate with the Serval platform | | `serval logout` | Log out from the Serval platform | | `serval status` | Show current authentication status | | `serval profile list` | List all profiles | | `serval profile use ` | Set the active profile | | `serval profile show [name]` | Show profile details | | `serval profile remove ` | Remove a profile | | `serval pull ` | Pull workflows, skills, and configuration for a specific team | | `serval push ` | Push local changes back to a team | | `serval access search [query]` | Browse roles available to request access to | | `serval access request` | Submit an access request for a role | | `serval access list` | View your access requests | | `serval access cancel ` | Cancel or revoke an access request | | `serval version` | Display the CLI version | | `serval help` | Show help for any command | | `serval completion` | Generate shell autocompletion scripts | ## Getting Started 1. [Install the Serval CLI](/sections/cli/installation) 2. Run `serval login` to authenticate 3. Use `serval pull ` to download your team's workflows and skills 4. Edit workflows and skills locally 5. Use `serval push ` to deploy your changes ## Next Steps * Learn how to [install the CLI](/sections/cli/installation) * Understand [pushing and pulling configuration](/sections/cli/push-pull-configuration) * Manage [access requests from the CLI](/sections/cli/access) # Push & Pull Configuration Source: https://docs.serval.com/sections/cli/push-pull-configuration Managing Serval workflows and skills locally with the CLI # Push & Pull Configuration The Serval CLI enables you to manage your team's workflows and skills locally, allowing you to use your preferred development tools and integrate with version control systems like Git. ## Authentication Before you can pull or push workflows, you need to authenticate with Serval: ```bash theme={null} serval login ``` This will initiate a device authentication flow: 1. The CLI will display a device code and URL 2. Visit the URL in your browser (e.g., `https://app.serval.com/auth/device?code=XXXX-1234`) 3. Confirm the authentication in your browser 4. The CLI will automatically detect successful authentication Example output: ``` 🔐 Device Authentication Required ================================ Please visit the Serval web app at https://app.serval.com/auth/device?code=XXXX-1234 Waiting for authorization... ✅ Successfully authenticated! ``` ### Signing in to another region `serval login` signs you in to the United States region. If your organization uses the European Union region, pass its application URL: ```bash theme={null} serval login --url https://app.eu1.serval.com ``` The CLI saves that URL in your profile after you sign in, so `pull`, `push`, and `access` reach the right region without repeating the flag. This requires CLI v0.5.7 or later. Earlier versions resolve the wrong API host and fail at sign-in with a `no such host` error, so run `serval version` if you are unsure. [Data residency](/sections/documentation/platform/data-residency) lists the regions Serval operates and the application URL of each. To check your authentication status: ```bash theme={null} serval status ``` To log out: ```bash theme={null} serval logout ``` ## Finding Your Team Prefix To work with a team's workflows, you need its prefix. You can find team prefixes by: 1. Visiting [admin settings](https://app.serval.com/admin/settings) in Serval 2. Navigating to the **Teams** section 3. Looking for the team prefix (e.g., `EXA`, `DEV`, `OPS`) The prefix is also included in the URL when you visit a team's workflows or tickets in the web app. When environments are enabled, you can use a non-live environment's prefix or the prefix of a branch you have access to. Pull and push still require the permissions for that team. ## Pulling Workflows and Skills To download a team's workflows, skills, and configuration: ```bash theme={null} serval pull ``` For example: ```bash theme={null} serval pull EXA ``` This creates a local directory structure: ``` teams/ └── EXA/ # Team directory ├── team.yaml # Team metadata ├── workflows/ # All workflows for this team │ ├── hello-world/ │ │ ├── index.ts # Workflow implementation │ │ └── workflow.yaml # Workflow metadata │ └── onboard-employee/ │ ├── index.ts │ └── workflow.yaml └── skills/ # All Help Desk and Catalyst skills for this team ├── resetting-passwords/ │ ├── SKILL.md # Skill instructions │ └── skill.yaml # Skill metadata └── reviewing-workflows/ ├── SKILL.md └── skill.yaml ``` ### Directory Structure * **teams/**: Holds one directory per team you have pulled * **Team Directory**: Named after the team prefix (e.g., `EXA/`) * **team.yaml**: Contains team-level metadata and configuration * **workflows/**: Contains all workflows for the team * **Workflow Folders**: Each workflow has its own directory with: * `index.ts`: The TypeScript implementation of the workflow * `workflow.yaml`: Workflow metadata and configuration * **skills/**: Contains all Help Desk and Catalyst skills for the team * **Skill Folders**: Each skill has its own directory with: * `SKILL.md`: The instructions the agent follows, written in Markdown * `skill.yaml`: Skill metadata ### Workflow Metadata (workflow\.yaml) Each workflow includes a `workflow.yaml` file with the following structure: ```yaml theme={null} name: Hello World description: This is the workflow description. slug: hello-world deployed: true approval_procedure: steps: - step_type: groups group_ids: - 01959d51-dcfg-7dfc-9e9b-742237d518c7 version: 1 ``` Key fields: * **name**: Display name of the workflow * **description**: Detailed description of what the workflow does * **slug**: URL-friendly identifier (must match the folder name) * **deployed**: Whether the workflow is active in Serval * **approval\_procedure**: Defines who can approve workflow runs * **version**: Workflow version number ### Skill Metadata (skill.yaml) Each skill has a `SKILL.md` file with the instructions the agent follows, written in Markdown, and a `skill.yaml` file with the following structure: ```yaml theme={null} name: Resetting Passwords description: Resets a user's password. Use when a requester says they are locked out or forgot their password. slug: resetting-passwords skill_type: help_desk should_always_use: false deployed: true id: 019f8c14-770d-76cb-a76a-a20040e8564c ``` Key fields: * **name**: Display name of the skill, written as a title with spaces * **description**: When the agent should use this skill. Leave it empty for an always-use skill * **slug**: Folder name for the skill (must match the folder name) * **skill\_type**: `help_desk` for a Help Desk Skill or `catalyst` for a Catalyst Skill * **should\_always\_use**: Whether the skill applies on every turn instead of only when it matches a request * **deployed**: Whether the version you pulled is the one the agent uses, the same meaning as `deployed` in `workflow.yaml` * **id**: Server-managed identifier that the CLI uses to match your local skill to the one in Serval References to workflows, other skills, users, and entitlements inside `SKILL.md` use the same mention syntax as the web editor, for example `<@workflow:wf_...>`. ## Editing Workflows and Skills Once pulled, you can edit workflows and skills using any text editor or IDE: 1. **Modify workflow code**: Edit the `index.ts` file to change workflow behavior 2. **Update metadata**: Modify `workflow.yaml` to change description, approval procedures, etc. 3. **Modify skill instructions**: Edit `SKILL.md` to change what the agent does, and `skill.yaml` to change the name, description, or always-use setting 4. **Test locally**: Use your standard TypeScript development tools 5. **Version control**: Commit changes to Git or your preferred VCS ## Pushing Changes After making local changes, push them back to Serval: ```bash theme={null} serval push ``` For example: ```bash theme={null} serval push EXA ``` The CLI will: 1. Validate your local changes 2. Compare with the remote state 3. Upload modified workflows and skills 4. Update workflow versions 5. Deploy changes if `deployed: true` ### Push Behavior * **New workflows**: Created if they don't exist in Serval * **Modified workflows**: Updated with your changes * **Deleted workflows**: Not automatically deleted (manual deletion required in UI) * **New skills**: Created when a `skills//` folder matches no existing skill by `id` or name * **Modified skills**: Name, description, instructions, and always-use changes are pushed; when `deployed` is true and the name, description, or instructions changed, the new version is published * **Unpublishing skills**: Setting `deployed: false` on a live skill does not unpublish it; unpublish from the web app * **Deleted skills**: Not automatically deleted (manual deletion required in UI) * **Validation**: The CLI validates YAML syntax and basic structure before pushing Pulling skills requires the team Viewer role or higher. Editing skills requires Drafter, and publishing them requires Builder. ## Working with Multiple Teams You can manage workflows and skills for multiple teams: ```bash theme={null} # Pull workflows and skills from different teams serval pull EXA serval pull DEV serval pull OPS # Your directory structure will be: # teams/ # ├── EXA/ # │ ├── workflows/ # │ └── skills/ # ├── DEV/ # │ ├── workflows/ # │ └── skills/ # └── OPS/ # ├── workflows/ # └── skills/ ``` ## Profiles Each profile stores the credentials and platform URL of a single organization. If you work in more than one, give each its own profile: ```bash theme={null} serval login --profile acme serval login --profile acme-eu --url https://app.eu1.serval.com ``` Signing in makes that profile active. To see your profiles and switch between them: ```bash theme={null} serval profile list # name, organization, URL, and token status serval profile use acme-eu # set the active profile serval profile show # details for the active profile serval profile remove acme # remove a profile ``` Every command accepts `--profile ` to select a profile for a single run, and the `SERVAL_PROFILE` environment variable sets it for a shell session. ## Best Practices ### Version Control 1. **Initialize Git** in your workflow directory: ```bash theme={null} git init cd EXA git add . git commit -m "Initial workflow commit" ``` 2. **Use branches** for workflow changes: ```bash theme={null} git checkout -b update-onboarding-workflow # Make changes git commit -m "Add manager approval to onboarding" # Review and merge in your VCS # After merging, push to Serval serval push EXA ``` ### Development Workflow 1. **Pull latest**: Always pull before making changes ```bash theme={null} serval pull EXA ``` 2. **Make changes**: Edit workflows locally 3. **Test**: Validate your TypeScript code 4. **Commit**: Save changes to version control 5. **Push**: Deploy to Serval ```bash theme={null} serval push EXA ``` # Analytics Source: https://docs.serval.com/sections/documentation/campaigns/analytics Track campaign delivery, monitor response rates, and export data for offline analysis After a campaign runs, you can track delivery and responses from the campaign detail page. The detail page has tabs for the campaign configuration, per-recipient conversations, and aggregated insights. *** ## Broadcast Analytics The insights view shows how message delivery progressed — total recipients, how many were delivered successfully, how many failed, and how many are still pending or scheduled. A delivery timeline shows when messages were sent and how send volume was distributed over time. For locally-scheduled campaigns, you can see distinct delivery clusters corresponding to each timezone batch. *** ## Response Analytics If your campaign has a [response workflow](/sections/documentation/workflows/overview) attached, the insights view also shows aggregated response data. You can track overall response progress and see breakdowns for each form field in the workflow — visualized by field type (e.g., bar charts for multiple choice, distributions for numbers, frequency lists for text). *** ## Exporting Data You can export campaign data as a CSV from the insights view. The export includes recipient details and, if a response workflow is attached, form field values for each respondent. Use this for offline analysis, reporting, or building a modified recipient list for a follow-up campaign. *** ## Conversations The conversations view provides a per-person list of every campaign recipient. You can filter by delivery status and response status to find specific people. Click any recipient to see their delivery details, failure reason (if applicable), response data, and a link to the conversation. You can also **retry** a failed delivery for an individual recipient from here. *** ## Related Run, stop, retry, and manage campaign lifecycle Understand resolution modes and recipient targeting Configure inputs for response collection workflows # Create a Campaign Source: https://docs.serval.com/sections/documentation/campaigns/create-campaign Walk through the campaign wizard to build, target, schedule, and send a campaign The campaign wizard guides you through creating a campaign in five steps: basics, recipients, schedule, message (including optional response workflow), and review. You can save your progress at any step and return later. The wizard preserves your draft in the browser session. You need the Builder role or higher to create campaigns. Your team must also have the Campaigns capability enabled and a delivery channel available — the embedded widget, a [Slack](/sections/integrations/slack) DM, a [Microsoft Teams](/sections/integrations/microsoft-teams) DM, or [email](/sections/documentation/helpdesk/email). *** ## Creating a New Campaign Navigate to **Campaigns** in the sidebar and click **New Campaign**. The wizard opens on the Basics step. Enter a **Name** and optional **Description** for your campaign. Select how you want to target recipients: * **Users & Groups** — Pick individual users and/or existing Serval user groups. All members of the selected groups receive the campaign message. * **CSV** — Upload a CSV file containing recipient email addresses. The CSV must include an `email` column. You can also include `timezone` and any custom columns that become template variables in your message. The wizard validates your selection and shows a preview of resolved recipients before you continue. For CSV uploads, the wizard checks for formatting issues and displays any row-level errors so you can fix them before proceeding. See [Recipients](/sections/documentation/campaigns/recipients) for detailed CSV formatting requirements. This step is also where you pick the **delivery channel** — how Serval sends your campaign: * **Slack DM** — Direct message via your connected [Slack integration](/sections/integrations/slack). * **Teams DM** — Direct message via your connected [Microsoft Teams integration](/sections/integrations/microsoft-teams). * **Email** — Sent via your team's [intake address](/sections/documentation/helpdesk/email). * **Embedded widget** — Starts a conversation in the recipient's [embedded widget](/sections/documentation/helpdesk/embedded-widget/overview). Available when your organization has an enabled configuration under **Organization Settings → Embedded Widget**. No Slack, Teams, or email integration is required. Slack, Teams, and email appear in the channel selector. Embedded widget appears only when your organization has an enabled widget configuration. The wizard pre-selects whichever channel is fully connected and flags any that aren't ready — for example, if Microsoft Teams is connected but the Serval bot isn't installed, or if no email intake address has been configured. Each campaign uses a single delivery channel. Choosing **Embedded widget** does not send a Slack DM, Teams DM, or email. The recipient sees the message as a conversation in widget history, marked unread until opened. Widget campaigns do not create a separate inbox notification. Numberless Slack, Teams, and email campaign conversations stay out of widget history; an escalated, numbered request appears with the user's other requests. A **Send preview** test opens in Serval web; preview tickets do not appear in the actual embedded widget. First choose how the campaign sends: * **One-time** — Send once. Pick immediate, a specific scheduled time, or local time per recipient. * **Recurring** — Send on a repeating schedule. Configure the frequency (e.g., every Monday, the 1st of each month) and delivery mode. * **Triggered** — Send on demand when a workflow fires it (e.g., on a webhook or a Serval event), rather than on a schedule. See [Scheduling](/sections/documentation/campaigns/scheduling) for all three modes, including [triggered](/sections/documentation/campaigns/scheduling#triggered) (workflow-fired) sends. Compose your campaign message using the rich text editor. You can format text with bold, italic, lists, and links. When viewed in the embedded widget, standard emoji shortcodes such as `:sunny:` and `:bulb:` display as emoji. Custom workspace emoji names stay as text. You can also @-mention people in the message: type `@` and choose **@Recipient** to address whoever the campaign reaches, or pick a specific user by name. In Slack DMs these become real @-pings. In Microsoft Teams and email, they render as the person's name in plain text. Use **template variables** to personalize the message for each recipient. Standard variables include: | Variable | Description | | - | - | | `{{Recipient.FirstName}}` | Recipient's first name | | `{{Recipient.LastName}}` | Recipient's last name | | `{{Recipient.FullName}}` | Recipient's full name | | `{{Recipient.Email}}` | Recipient's email address | If you uploaded a CSV with additional columns, those column headers are also available as template variables with a `CSV.` prefix. For example, a CSV column named `department` becomes `{{CSV.department}}` in the message editor. Serval automatically translates the campaign message body (and email subject) into each recipient's language before sending, so a single campaign reaches everyone in their own locale. Template variables are filled in after translation, so personalized values stay intact. This applies across Slack, Microsoft Teams, email, and the embedded widget. **Response workflow (optional):** To collect structured feedback, select any deployed workflow. Slack and Teams recipients select **Respond** to open the workflow's [input form](/sections/documentation/workflows/Configure/inputs). Embedded widget recipients complete the form in the conversation and select **Submit**. Campaigns always present the form and wait for the recipient's submission, even if the workflow doesn't have form confirmation enabled elsewhere. **Allow recipients to dismiss:** When a response workflow is attached, recipients also see a **Dismiss** button by default, letting them decline the form. Turn off **Allow recipients to dismiss** to remove that button — recipients can still submit the form. This prevents accidental dismissals (which can't be undone) and keeps your response analytics focused on real responses. The setting applies across every channel (Slack, Teams, email, and the embedded widget). **Post a reply prompt in the thread (Slack only):** For Slack DM campaigns, Serval posts a short prompt in the message thread telling recipients where to reply. It's on by default. The prompt is a second Slack message per recipient, so turning it off sends one message instead of two and can nearly double send speed on large campaigns. Smaller campaigns see little difference, so leave it off for one-way announcements that don't collect replies. The form can include any [workflow input types](/sections/documentation/workflows/Configure/inputs): multiple choice, scales, short text, dates, checkboxes, and file uploads. The review step lets you preview the form as recipients will see it. Because each response is a real workflow run, you can wire branching and actions into the workflow itself. If you don't need to collect responses, leave this unset. The review step summarizes your campaign configuration: name, recipient count and resolution mode, schedule, message preview, and response workflow (if any). Review the details and click **Save** to create the campaign as a draft. It won't send until you explicitly run or activate it. *** ## Editing a Draft Campaign You can edit any campaign that hasn't been run or activated yet. Open the campaign from the list and click **Edit**. The wizard reopens with your saved values so you can update any step. Once a campaign has been run or activated, you can no longer edit its configuration. If you need to make changes, stop the campaign and duplicate it with the corrected settings. # Manage Campaigns Source: https://docs.serval.com/sections/documentation/campaigns/manage-campaigns Run, activate, stop, retry, duplicate, archive, and delete campaigns throughout their lifecycle Once a campaign is created, you manage it through its lifecycle: run or activate it, stop it mid-send, retry failed recipients, duplicate it for reuse, or archive and delete it. This page covers each action and how campaigns move between statuses. *** ## Campaign Lifecycle One-time campaigns move from draft to sending to sent. You can stop a campaign mid-send and retry later. Recurring campaigns follow the same pattern, but the parent series manages the schedule and each fire creates a new **run** that has its own delivery lifecycle. [Triggered campaigns](/sections/documentation/campaigns/scheduling#triggered) share the recurring lifecycle — you **Activate** to arm them and **Pause** to stop fires — except a workflow, not a schedule, decides when each run happens. The campaign detail page always shows the current status and the actions available at that stage. *** ## Running a One-Time Campaign To send a one-time campaign, open it from the campaign list and click **Run**. A confirmation dialog shows the recipient count and schedule summary so you can verify before sending. What happens when you run depends on the schedule type: * **Immediate** — Serval begins delivering messages to all recipients right away. * **Scheduled** — If the chosen time is in the future, the campaign waits until then. If the time has already passed, messages send immediately. * **Local time** — Serval groups recipients by timezone and delivers to each batch at the appropriate local time. The campaign list polls for status updates while any campaign is actively running, so you can monitor progress in real time. *** ## Activating a Recurring Campaign Recurring campaigns use **Activate** instead of Run. Open the series campaign and click **Activate**. A confirmation dialog explains that the schedule will begin firing automatically. Once activated: * If **Run immediately** is enabled (the default), the first run starts right away. * Subsequent runs are created automatically each time the schedule fires. * Each run appears on the **Runs** tab of the parent campaign, where you can drill into its delivery and response data. *** ## Stopping and Resuming ### Stopping a one-time campaign Click **Stop** on a running or scheduled campaign. Messages already delivered are not recalled, but messages not yet sent are skipped. ### Pausing a recurring campaign Click **Pause** on an active series. No new runs are created while the schedule is paused. Any run that was already in progress continues its own send lifecycle independently. ### Resuming a recurring campaign Click **Resume** on a paused series. The schedule resumes from the next fire time. Serval does not retroactively create runs for fires that were missed while paused. Stopping or pausing a campaign does not delete it. You can retry, resume, or duplicate it later. *** ## Retrying Failed or Unsent Recipients If some messages fail to deliver (e.g., the recipient isn't reachable via the configured channel) or you stopped a campaign before all messages were sent, you can retry those recipients. ### Bulk retry Open a stopped or completed campaign and click **Run** again. Serval offers to retry all unsent and failed recipients without re-sending to recipients who already received the message. ### Single recipient retry On the **Conversations** tab, find the specific recipient who failed and click **Retry**. Serval attempts delivery to just that person. *** ## Duplicating a Campaign You can duplicate any campaign to create a new draft based on its configuration. Open the actions menu and select **Duplicate**. Serval copies the following into a new draft: * Campaign name and description * Message template * Schedule configuration (including recurring schedule, if applicable) * Target recipients (users and groups) ### Cross-team duplication When duplicating, you can choose to create the copy in a different team. You can duplicate into any destination team where you have permission to create campaigns. The built-in **Builder** and **Manager** roles hold this permission, and it can also be [granted through a custom role](/sections/documentation/platform/permissions#custom-team-roles). If multiple teams need to send similar communications, duplicate the campaign and adjust the recipients and details for each team. After duplicating, the new campaign opens as a draft so you can review and modify it before running. *** ## Promoting a Campaign With **Test & Release** enabled, you can include a draft campaign in a review for another environment. The review preserves its delivery channel, including **Embedded widget**, and its feedback workflow reference. Applying the promotion saves a draft; it doesn't start delivery. Check the destination's channel configuration before activating or running the campaign. ## Archiving a Campaign You can archive campaigns you no longer need in your active list. Open the actions menu and select **Archive**. Archived campaigns are hidden from the main campaign list but can be viewed in the archived campaigns view and unarchived if needed. *** ## Deleting a Campaign You can delete a campaign that is still in draft. Open the actions menu and select **Delete** to permanently remove it. *** ## Related Walk through the campaign wizard step by step Track delivery progress and response data One-time, recurring, and triggered scheduling options Build workflows for campaign response collection # Campaigns Source: https://docs.serval.com/sections/documentation/campaigns/overview Broadcast messages and collect structured responses with workflows Campaigns let you broadcast a templated message to many people at once and collect responses through attached [workflows](/sections/documentation/workflows/overview). Recipients tap **Respond** to complete a structured form, and each response is a real **workflow run**—so everything your team already builds in [Catalyst](/sections/documentation/catalyst/overview) (branching, approvals, integrations) can run from campaign responses, not just static survey data. Deliver campaigns over **Slack DM**, **Microsoft Teams DM**, **email**, or the **embedded widget**. Target users, groups, or a CSV (columns personalize the message). Send once immediately, at a scheduled time, at each recipient's local timezone, or on a **recurring** cadence that repeats automatically—or fire a campaign on demand from a workflow with a [**triggered** campaign](/sections/documentation/campaigns/scheduling#triggered). Response workflows work on all four channels. Embedded widget recipients open the campaign conversation from widget history and fill out the form there; only successfully delivered widget campaigns appear in that history, marked unread until opened. Numberless Slack, Teams, and email campaign conversations stay out of widget history; an escalated, numbered request appears with the user's other requests. Slack and Teams DM recipients tap **Respond** to fill out the form in their chat client; email recipients tap **Respond** to open a hosted form page on your Serval domain (and **Dismiss** for a one-click "no thanks" landing page). Free-text email replies still thread back to the campaign conversation alongside any structured form responses. To ask a question or share an update, reply in the campaign's Slack thread, your Microsoft Teams DM, the email, or the conversation in the embedded widget. If you've received several campaigns, mention which one you're replying to. To fill out the campaign's form, select **Respond**, or complete it directly in the embedded widget conversation. *** ## Getting Started Walk through the campaign wizard step by step Target your audience with users, groups, or CSV uploads One-time, recurring, or workflow-triggered delivery Run, activate, stop, retry, and archive campaigns Track delivery, responses, and export data *** ## Prerequisites Before you can create and send campaigns, your team needs: * **Campaigns enabled**: A team admin must enable the Campaigns capability in **Team Settings** > **Capabilities**. See [Permissions](/sections/documentation/platform/permissions#capabilities-toggle) for details. * **A delivery channel available**: Each campaign is sent over a single channel: the embedded widget, a [Slack](/sections/integrations/slack) DM, a [Microsoft Teams](/sections/integrations/microsoft-teams) DM, or [email](/sections/documentation/helpdesk/email). Slack and Teams need direct messaging enabled on the integration; email needs an intake address configured. See [Create a Campaign](/sections/documentation/campaigns/create-campaign) for how the wizard surfaces available channels. * **Create permission**: You need the [Builder role](/sections/documentation/platform/permissions#team-roles) or higher to create and edit campaigns. The Viewer role can view campaigns and analytics. *** ## Related Build response workflows that campaigns use to collect structured feedback Connect Slack for campaign delivery Connect Microsoft Teams for campaign delivery Set up an email intake address for email campaign delivery Understand the Builder role required to create campaigns # Recipients Source: https://docs.serval.com/sections/documentation/campaigns/recipients Target your campaign audience using users and groups or CSV uploads Every campaign needs a defined set of recipients. When you create a campaign, you choose a resolution mode that determines how Serval builds the recipient list. *** ## Resolution Modes ### Users & Groups Pick individual users and/or existing Serval user groups. All members of the selected groups receive the campaign message. * You can combine individual users and groups in the same campaign. Serval deduplicates recipients who appear in more than one group or are also selected individually. * Recipients are resolved at the time you run the campaign, so any group membership changes between creation and execution are reflected. * Template variables like `{{Recipient.FirstName}}`, `{{Recipient.LastName}}`, and `{{Recipient.Email}}` are populated from each user's Serval profile. ### CSV Upload Upload a CSV file to define a custom recipient list. Use this when your audience doesn't map to existing users and groups, or when you need to include custom data fields in your message. #### Required columns | Column | Description | | - | - | | `email` | Recipient's email address (must match a Serval user) | #### Optional columns | Column | Description | | - | - | | `timezone` | Recipient's IANA timezone (e.g., `America/New_York`). Required for [local-time scheduling](/sections/documentation/campaigns/scheduling#local-time). | | Any other column | Becomes a custom template variable in the message editor | #### How it works 1. Upload your CSV file in the recipients step of the campaign wizard. 2. Serval validates the file and displays a preview with any row-level errors (missing emails, invalid timezones, unrecognized formats). 3. Fix any errors and re-upload, or proceed if validation passes. 4. Recipients are stored when you save the campaign. They don't change if you update the CSV file externally. #### Custom template variables All columns become template variables with a `CSV.` prefix. For example, a CSV with columns `email`, `timezone`, `department`, and `office_location` makes `{{CSV.department}}` and `{{CSV.office_location}}` available for personalization in the message editor. Custom variable names are derived from your CSV column headers exactly as written. Use clear, descriptive headers like `department` or `start_date` so they're easy to identify in the message editor. #### Example CSV ```csv theme={null} email,timezone,department,manager_name alice@company.com,America/New_York,Engineering,Jordan Lee bob@company.com,America/Los_Angeles,Design,Sam Park carol@company.com,Europe/London,Engineering,Jordan Lee ``` This CSV makes the following template variables available: `{{CSV.department}}` and `{{CSV.manager_name}}`, in addition to the standard variables (`{{Recipient.FirstName}}`, `{{Recipient.LastName}}`, `{{Recipient.FullName}}`, `{{Recipient.Email}}`). # Scheduling Source: https://docs.serval.com/sections/documentation/campaigns/scheduling Control when campaign messages are delivered: once, on a recurring cadence, or fired on demand by a workflow When you create a campaign, the schedule step asks how it should send: one-time, recurring, or triggered. One-time and recurring are clock-based. Triggered hands timing off to a workflow. This page covers all three. *** ## Choosing How to Send The schedule step opens with three modes: * **One-time**: Send the campaign once. Choose immediate, scheduled, or local-time delivery. * **Recurring**: Send on a repeating schedule. Serval automatically creates a new run each time the schedule fires. * **Triggered**: A [workflow](/sections/documentation/workflows/overview) decides when the campaign fires, whether on an incoming webhook, a Serval event, a schedule (cron) you build, or any condition. A scheduling workflow can drive it on a cadence like a recurring campaign, and can *also* react to events and branch on logic. Pick one-time for announcements, event logistics, or any message that only needs to go out once. Pick recurring for periodic check-ins, pulse surveys, or any communication you want to repeat on a cadence. Pick triggered when *something else* decides when to send. *** ## One-Time Schedules One-time campaigns support three delivery modes. An email campaign to a very large audience sends over multiple days when the audience is bigger than the account can email in one day. Before you launch (immediate or scheduled), the run dialog tells you roughly how many days the send will take. It continues on its own, with no action needed from you. ### Immediate When you run the campaign, Serval starts delivering to all recipients right away. **Best for:** Urgent announcements, time-sensitive updates, or situations where delivery timing doesn't matter. ### Scheduled Pick a specific date, time, and timezone. All recipients receive the message at the same moment. **Best for:** Coordinated announcements tied to a specific moment, such as a product launch, a policy effective date, or a scheduled maintenance window. If you run a scheduled campaign before the chosen time, Serval queues the messages and delivers them when the time arrives. If the time has already passed, messages are sent immediately. ### Local Time Pick a wall-clock time, and each recipient receives the message at that time in their own timezone. Serval groups recipients into timezone batches and delivers each batch when the chosen time arrives in its timezone. Between batches, the campaign status shows **Waiting for next batch**. **Best for:** Messages that should arrive during business hours for each recipient, such as a benefits enrollment reminder or an IT survey. *** ## Recurring Schedules Recurring campaigns repeat on a cron-based schedule. When you select **Recurring**, you configure three things: frequency, delivery mode, and whether to run immediately on activation. ### Frequency Choose how often the campaign fires: | Frequency | What you configure | | - | - | | **Every N minutes** | Interval in minutes (minimum 15) | | **Every N hours** | Interval in hours | | **Day of the week** | Select specific weekdays (for example, every Monday and Wednesday) plus a time of day | | **Day of the month** | Select specific dates (for example, the 1st and 15th) plus a time of day. You can also select "last day of month." | | **Month(s)** | Select specific months, specific days within those months, and a time of day | For day-of-week, day-of-month, and month frequencies you also pick a time of day and timezone for delivery. ### Delivery mode For fixed-time frequencies (day of week, day of month, months), you choose how the time is interpreted: * **Specific timezone**: Everyone receives the message at the same moment, using the timezone you selected. * **Local time**: Each recipient receives the message at the chosen time in their own timezone, the same way [one-time local scheduling](#local-time) works. Minute and hour interval schedules always deliver to everyone at the same time. The local-time option is only available for fixed-time frequencies. ### Run immediately When you activate a recurring campaign, you can choose whether to fire the first run right away or wait for the next regular cycle: * **Run immediately** (default): The first run starts as soon as you activate the series. For local-time delivery, recipients whose local time has already passed that day receive the message right away. * **Wait for next cycle**: The series waits until the next scheduled fire time before sending the first run. ### Upcoming sends preview The schedule step shows a preview of the next several upcoming send times so you can verify the cadence is correct before activating. ### Runs Each time a recurring schedule fires, Serval creates a new run that goes through its own send lifecycle. You can view all runs from the parent campaign's **Runs** tab and drill into any individual run to see its delivery and response data. *** ## Triggered A triggered campaign sends when a [workflow](/sections/documentation/workflows/overview) fires it, through the **Trigger Campaign** action: the workflow owns the timing, instead of a fixed schedule set on the campaign. Each fire sends the campaign's message to its configured recipients, with per-fire values passed in from the workflow. What sets off that workflow is up to you: an incoming webhook from another system, a Serval event (a ticket created, access granted), a schedule (cron) you build in Workflows, or any condition you can express. So "triggered" isn't limited to external events: a scheduling workflow can drive it on a cadence the way a recurring campaign does, while *also* reacting to events and branching on logic that a plain schedule can't. ### How it works A triggered campaign is a template: a saved message, recipient list, and delivery channel that never sends on its own. A workflow fires it by calling the **Trigger Campaign** action with the campaign's ID. Each fire spawns a new run, like a recurring campaign's runs. It delivers to the campaign's configured recipients the moment it fires, filling any `{{Trigger.*}}` variables in the message with values the workflow passes in. The trigger controls *when* the campaign sends and supplies per-fire variables. It doesn't choose recipients: those stay statically configured on the campaign (users, groups, or a CSV), exactly like a one-time or recurring campaign. ### When to use it | Scenario | Why triggered | | - | - | | An external system posts a webhook ("new hire added in the HRIS") and you want to message that person | The webhook payload drives the send and personalizes it | | A Serval event (ticket escalated, access granted) should kick off a templated message | A workflow listens for the event and fires the campaign | | Send logic too complex for a cron schedule (conditional, multi-step) | The workflow decides whether and when to fire | For a straightforward time-based send, the built-in [one-time](#one-time-schedules) or [recurring](#recurring-schedules) modes are simpler: no workflow needed. Reach for triggered when an external system, a Serval event, or conditional logic should decide when to send, or when you want the schedule to live in a workflow alongside other steps. ### Creating a triggered campaign Create a campaign as usual (see [Create a Campaign](/sections/documentation/campaigns/create-campaign)). On the **Schedule** step, pick **Triggered**. The date/cadence options are replaced with a panel explaining that the campaign fires from a workflow. Compose the message as normal. Wherever you want a value the workflow supplies per fire, insert a [trigger variable](#trigger-variables) like `{{Trigger.incidentTitle}}`. Per-recipient `{{Recipient.*}}` variables still personalize each message alongside them. Save to create the campaign as a draft. Saving assigns the campaign an ID: the workflow needs this ID to fire it. Once the campaign is saved, the triggered panel shows the ID, ready to copy. From the triggered panel, click **Create trigger in Workflows**. Serval opens the workflow builder pre-seeded to wire up the **Trigger Campaign** action for this campaign, including any trigger variables your message references. When you build it, you choose how the workflow is triggered: a webhook, a Serval event, a schedule, or another trigger. Back on the campaign, click **Activate**. Only an active campaign fires: until you activate it, the workflow's calls are ignored (nothing sends). Pause it any time to stop fires without deleting it. ### Trigger variables Trigger variables carry values from the workflow into the message. Reference one as `{{Trigger.}}` in the message or subject, for example `{{Trigger.incidentTitle}}`. A trigger variable is one value per fire: the *same* for every recipient of that send. That's different from `{{Recipient.*}}` and `{{CSV.*}}` variables, which vary per recipient. Use trigger variables for facts about the event that fired the campaign (an incident title, a system name), and recipient variables to address each person. You can use both in the same message. For example, `Hi {{Recipient.FirstName}}, a new incident ({{Trigger.incidentTitle}}) was opened. Please take a look.` renders each recipient's own first name next to the one incident from this fire. (Note that `{{Trigger.*}}` doesn't address the recipient: the campaign sends to its statically configured recipients, and the trigger value is shared across all of them.) The set of `{{Trigger.*}}` keys your message references is the campaign's fire-time contract: every referenced key must be supplied on each fire, or that fire is rejected and nothing sends. (An empty value is allowed, but a *missing* key isn't.) The workflow you build from **Create trigger in Workflows** is pre-seeded to map each key, so it satisfies the contract out of the box. Trigger variables only resolve for a triggered campaign. If you reference `{{Trigger.*}}` in a one-time or recurring campaign, Serval flags it and blocks activation: those campaigns have no trigger to fill the value. You can preview how the message renders, and use **Send preview** to send yourself a test with sample values for each trigger variable, before activating. ### Wiring the workflow The **Trigger Campaign** action is what fires the campaign from a workflow. **Create trigger in Workflows** sets it up for you, but it helps to understand what it does: | Input | Purpose | | - | - | | **Campaign** | The campaign to fire, by ID. | | **Trigger variables** | The values that fill `{{Trigger.*}}` in the message, read from the trigger payload. Supply every key the message references. | | **Event ID** *(optional)* | A stable de-duplication key. See below. | Serval de-duplicates fires by event ID so the same event never sends twice: * **Provide an event ID** (for example, the webhook's delivery ID) and re-deliveries of that same event are ignored: the campaign fires exactly once for that event, even if the workflow runs again later. * **Omit it** and the event ID defaults to the workflow run's ID, so an automatic retry of a run doesn't double-send: one run, one send. A new run sends again. Don't hardcode a constant event ID. Serval treats it as "this one event," so the campaign would fire once and then quietly ignore every later call. Use the trigger's natural delivery ID, or omit it to get one-send-per-run. ### Activating, pausing, and runs Triggered campaigns use the same lifecycle as recurring campaigns: **Activate** to arm the campaign so workflow fires send, **Pause** to stop sending on new fires (a run already in progress finishes), and **Resume** to re-arm it (fires that arrived while paused aren't replayed). Each fire creates a run on the campaign's **Runs** tab with its own delivery and response data. ### Good to know * **Recipients are static.** The trigger fires the send and supplies per-fire variables, not the audience. Set recipients on the campaign itself. * **Activate it first.** A draft or paused campaign ignores fires (nothing sends, and the workflow doesn't error). * **Same team only.** A workflow can only fire campaigns in its own team. *** ## Choosing a Schedule | Scenario | Recommended mode | | - | - | | "Send this right now" | One-time: Immediate | | "Everyone should see this at 2:00 PM ET on March 15" | One-time: Scheduled | | "Everyone should see this at 9:00 AM their time" | One-time: Local time | | Urgent security notice or outage alert | One-time: Immediate | | Weekly IT satisfaction pulse every Monday | Recurring: Day of week, local time | | Monthly compliance check on the 1st | Recurring: Day of month | | Quarterly tool check-in | Recurring: Month(s), select Jan/Apr/Jul/Oct | | "When our HRIS posts a new hire, welcome them" | Triggered: fired by a workflow | | "When a ticket is escalated, message the requester" | Triggered: fired by a workflow | *** ## Related Walk through the campaign wizard step by step Run, activate, stop, and manage campaign lifecycle Build the workflow that fires a triggered campaign Track delivery progress and response data # Background agents Source: https://docs.serval.com/sections/documentation/catalyst/agents Set up agents that run on a schedule and surface findings for you to review Background agents are Catalyst runs that execute on a schedule without you sending each message manually. An agent works over your team's tickets, workflows, databases, and connected apps on a recurring cadence, then surfaces what it found as a **finding** you can review, act on, or dismiss. Use background agents for recurring, proactive work: summarizing the last day of tickets, scanning your device fleet for at-risk endpoints, reclaiming unused licenses, or spotting automation opportunities across your ticket volume. Catalyst New agent screen with a prompt box to build a custom agent and a list of ready-to-use agents to install ## How background agents work 1. The agent runs on its schedule (or when you run it manually). 2. Each run is a Catalyst session you can open to see exactly what the agent did. 3. When a run produces something worth reviewing, it becomes a **finding** in the **New findings** feed on the Background Agents page. 4. You review the finding and apply, propose, dismiss, or acknowledge it. A run only becomes a finding when it produces reviewable substance: an action the agent took or a highlight worth surfacing. Runs that find nothing actionable complete without creating a finding. ## Create an agent You can start from a blank agent or install a prebuilt one. Go to **Background Agents** in the team sidebar. It opens to your findings feed; the top right has **New agent**, **Agent library**, and **Past findings**. Click **New agent**. In the **Build your custom agent by providing instructions** box, describe what you want the agent to do, and Catalyst opens a chat session and drafts it for you. Alternatively, install a prebuilt agent from **Browse ready to use agents** on the same screen (see [Installable agents](#installable-agents)). Catalyst drafts the agent and opens it in the resource panel marked **Unpublished changes**. Review the configuration (below), adjust anything you want, then click **Publish** to start it running. Until you publish, the agent stays a draft. ### Agent configuration Catalyst writes a first draft of the agent from your description, and you refine it. The agent's **name** appears as its title and can be edited. Review and change these settings in the resource panel while building, or later on the agent's **Agent configuration** tab. The sections are the same in both places. The system prompt that runs every time the agent runs: what to look at, what to do, and what to produce. When the agent runs. **Run manually** is always available. Add a schedule to have it run on its own: hourly, daily, on weekdays, or weekly, with a time of day (and the days of the week for a weekly schedule). Start times may vary by a few minutes. **Run as** sets the user whose permissions the agent uses while it runs, so it can only see and do what that user can. **Share runs with team** controls visibility: when it's off, runs are visible only to the run-as user and org admins. The agent always asks for approval before running a workflow that makes changes; read-only workflows run without asking. Add workflows here to let the agent run them without approval. Who to notify, and when. Choose a **Notification method** (send to a **Recipient**, or use **Custom agent instructions**), then set the **Notification conditions**: **Report ready** (the agent produced a report), **Action required** (it needs your input to proceed), and **Session completed** (it finished, regardless of outcome). The **Run as** user determines the agent's permissions on every run. If that user's access changes, the agent's capabilities change with it. ## Installable agents Instead of writing instructions from scratch, install a prebuilt agent for a common use case and customize it. Each ships with a recommended schedule you can change. Find installable agents from the Background Agents page: click **New agent**, then look under **Browse ready to use agents**. Search the list, and each card shows whether it's already **Installed** and who built it. | Agent | Cadence | What it does | | - | - | - | | **Daily Ticket Digest** | Daily | Summarizes new and unresolved tickets from the last 24 hours and highlights what needs attention, with links back to each ticket. | | **Service Desk QA / Quality Review** | Daily | Grades how human agents handled escalated tickets on clarity, correctness, comprehension, and collaboration, and produces a coaching scorecard. | | **Proactive Device & Endpoint Remediation** | Daily | Scans the device fleet for at-risk endpoints, flags emerging issues, and drafts remediations for you to review. | | **Ticket Trend & Volume Analytics** | Weekly | Tracks week-over-week ticket volume by category and surfaces the most common and critical failure patterns. | | **Automation Opportunity Finder** | Weekly | Reviews recent tickets for repetitive, manual requests with no coverage and drafts the top workflows and help desk skills for you to review and publish. | | **Proactive License Reclamation** | Weekly | Finds unused application licenses, reports the savings, and drives reclamation through your deprovision workflows. | | **Identity Audit Log Anomaly Watch** | Daily | Watches your identity provider's audit log for suspicious sign-in and privilege activity, reports only what clears a stated threshold, and never changes an account itself. | When an installed agent gets a new version, its entry shows **New version available** so you can pull in the updated instructions. ## Review findings Each finding is the agent's pitch for a single run. The Background Agents page opens to your findings feed, split into **New findings** and **Marked as read**. Open a finding to see: * **Highlights**: the key points on why the run matters. * **Activity**: the concrete actions the agent took during the run. * **Sources**: the tickets, resources, and web pages the agent drew on. * **Changes to review**: any staged changes (workflows, skills, knowledge) the agent drafted, ready to inspect before publishing. From a finding you can: * **Apply** the suggested changes, or **Propose for review** on teams that require approval before publishing (see [Changes and reviews](/sections/documentation/catalyst/changes-and-reviews)). * **Dismiss** the finding when there are staged changes you don't want. * **Acknowledge** the finding to clear it when there is nothing to apply. * **Chat about this** to open the agent's session and continue the work in Catalyst. Findings you have already handled move to **Past findings** (top right), organized into **Applied**, **Acknowledged**, and **Dismissed** tabs and filterable by agent, where you can revisit them and open the underlying run. ## Manage agents Open **Agent library** (top right of the Background Agents page) to see your active agents, each showing its owner and its schedule or trigger. Open one to reach its **Agent configuration** and **All runs** tabs, where you can **Run agent** on demand, **Pause schedule** to stop scheduled runs without losing the agent or its history (resume it later), **Open in Catalyst** to keep working on it in a chat, or **Delete agent**. Every run, scheduled or manual, creates a Catalyst session you can open to inspect exactly what the agent did. ## Learn more The Catalyst chat surface and resource pane How staged changes are reviewed and published Build automations with Catalyst Who can create and manage agents # Building workflows Source: https://docs.serval.com/sections/documentation/catalyst/building-workflows How to build and edit workflows with Catalyst: prompting, manual edits, versioning, and temporary workflows Catalyst can create and modify workflows through conversation. Most authoring starts in **Chat**, with results opening as tabs in the **resource panel** on the right. *** ## Natural language prompting Describe what you want in plain language. Catalyst searches your team (workflows, tickets, knowledge, connected apps), drafts workflow code, and stages changes for review. ### Tips for effective prompts * **State the outcome**: "Create a workflow that provisions Okta access when a manager approves" * **Name integrations**: mention the dependent apps you expect to use * **Reference existing resources**: "Update the @password-reset workflow to also notify the security channel" * **Ask Catalyst to check first**: "Search installable workflows before writing one from scratch" After Catalyst creates a workflow, it asks whether you want to test it. Testing is recommended but optional, and only runs when you explicitly agree. *** ## Workflow tab You are not limited to chat. When Catalyst opens a workflow in the resource panel, you can make adjustments on the summary view or edit the TypeScript code directly. When you start a new chat using a workflow’s **Run** button or the `/` workflow picker, the chat title includes the workflow name, such as **Run Onboarding**. Running a workflow in an existing chat preserves its established title. Hover over the version status in the action bar and select **Full version history** to explore published versions and drafts. Use **Compare versions**, when available, to inspect differences. For workflow version history outside an active session, see [Workflow versioning](/sections/documentation/workflows/Manage/versioning). Catalyst chat and resource panel showing an Okta MFA reset workflow draft ready to publish ### Published vs unpublished changes Catalyst stages new and updated workflows as drafts. The **Publish** button on a workflow tab applies the change and exposes it to the help desk agent. When **Require approval before publishing** is enabled under **Settings → Catalyst → Approval settings → Catalyst**, direct **Publish** is hidden. Publishing happens through structured reviews with designated approvers. See [Changes and reviews](/sections/documentation/catalyst/changes-and-reviews) for the full flow and settings. *** ## Connecting external apps Catalyst needs working integrations before it can call Okta, Slack, Jira, and other services in workflows. When an app integration is missing or needs credentials, Catalyst shows **Configure integrations** cards in chat. Each card shows the service and a **Connect**, **Configure**, or **Reconfigure** action: * **Connect**: Built-in service not yet connected: starts OAuth or setup and creates the app instance * **Configure**: App instance exists but authentication is incomplete * **Reconfigure**: App is connected but credentials or scopes need refresh Catalyst chat showing a Configure integrations card with a Connect action Complete the setup by following card instructions. Credentials go directly to the integration, not through chat. Catalyst won't ask you to paste API keys, client secrets, or passwords in the message thread. Don't paste secrets into chat. Use the in-chat setup cards instead. If you do paste a secret in chat, Catalyst won't use it. As a security best practice you should rotate any secrets posted into chat. After you finish connecting, the card updates automatically. ### Choose which instance a step uses If you connect more than one instance of the same app (for example, separate Okta tenants for US and EU employees), a workflow step could match any of them. To specify, select the specific instance a step should call from the instance dropdown, so there's no ambiguity about which one runs. Different steps can target different instances. *** ## Temporary workflows Catalyst sometimes creates a **temporary workflow**, a short-lived workflow used to probe an API, fetch data, or validate an integration before building the real automation. Temporary workflows are not published to your team's catalog. When Catalyst proposes a temporary workflow, a card appears in chat showing: * The workflow name and a link to open it in the resource panel * **Run** and **Reject** actions (unless the workflow is read-only, in which case it runs automatically) Catalyst chat showing a temporary analysis workflow auto-approved as read-only and completed *** ## Confirming workflow inputs When Catalyst runs a workflow that requires input confirmation, it presents the workflow's inputs as a **Confirm workflow inputs** form in chat instead of starting the run right away. Catalyst prefills any values it already gathered from the conversation. You review the inputs, complete or adjust them, and select **Confirm** to start the run. *** ## Related What Catalyst can do Get familiar with the Catalyst interface Open your first session and publish a change Using Catalyst to analyze ServiceNow tickets and build automations Stage changes, propose reviews, and configure approvers Building analytics dashboards with Catalyst # Catalyst skills Source: https://docs.serval.com/sections/documentation/catalyst/catalyst-skills Teach Catalyst how to build your workflows and automations Catalyst skills provide a way to teach Catalyst about how to build your workflows and common automations. Skills page with the Catalyst Skills tab selected, showing the skill list and publish-status filters To create a skill, do the following: 1. From the team sidebar, open **Skills**. 2. In the top-right corner, click **New skill**. 3. In the **Create a new skill** modal, choose **Catalyst Skill**. Create a new skill modal with Help Desk skill and Catalyst skill options ## Catalyst skills vs Help Desk skills Catalyst skills are distinct from Help Desk skills. The two are compared in the table below. | | Help Desk skills | Catalyst skills | | :-: | :-: | :-: | | How Serval uses them | The help desk agent handling employee requests | Catalyst when building automations | | Where to manage them | **Skills → Help Desk Skills** tab | **Skills → Catalyst Skills** tab | | Purpose | How the agent behaves when handling requests: tone, procedures, when to run workflows | Reusable context and instructions for Catalyst: team conventions, naming, deployment patterns | | Visible to end users | Indirectly, through agent responses | No: builders only | For more information, see [Help Desk skills](/sections/documentation/skills/overview). ## Examples * **Help Desk skill**: "When someone asks for laptop replacement, gather the reason, run the laptop-request workflow, and set expectations on turnaround time." * **Catalyst skill**: "Our team prefix is ENG. Always use installable workflows for Okta group changes when one exists." *** ## Related Build automations in the Catalyst chat Instructions for the help desk agent on end-user requests # Catalyst workspace Source: https://docs.serval.com/sections/documentation/catalyst/catalyst-workspace Get familiar with the Catalyst interface The **Catalyst** page is where you build automations by prompting the Catalyst agent. The page is accessed from the team sidebar and has two views: **Chat**, where you work with Catalyst, and a **Reviews** view for approving drafted changes (for teams that require approval before publishing). Catalyst chat view showing Quickstart buttons and the message composer *** ## Chat Chat with Catalyst to build automations from natural language descriptions. Above the chat composer are a number of ways to get started quickly, including **Quickstart**, **Browse prompts**, **Workflow types**, and **Install workflows**. ### Team vs private chats Every Catalyst chat has a visibility setting: * **Team chat**: Anyone on the team with Catalyst access * **Private chat**: Only you Choose visibility when starting a new chat from the picker on the composer. For an existing session, use the visibility picker in the chat header to switch between team and private. Use **private chat** for experiments you are not ready to share. Switch to **team chat** when you want collaborators to find the session in the sidebar or continue the work. ### Fast vs thinking mode Catalyst offers **Fast** and **Thinking** modes that trade off between speed and depth of reasoning: * **Fast:** Best for quick edits, small changes, or straightforward questions * **Thinking**: Best for complex implementations and multi-step builds Select the mode from the dropdown in the chat composer. The choice applies to the current chat and is remembered per chat. Managers can set a **default chat mode** under **Settings → Catalyst**. New sessions start with that default and individual users can still change mode in the composer. ### Read responses while Catalyst works Scroll up in the conversation to pause automatic scrolling. New output continues to arrive without moving the text you're reading. Scroll back to the bottom or select **Jump to bottom** to follow new output again. Sending a message also returns you to the latest output. You can also scroll up inside an expanded **Thinking** panel to pause scrolling there. The panel stays open when thinking finishes so you can keep reading. ### Interactive cards in chat Catalyst sometimes renders interactive UI in the message thread instead of plain text. #### Configure integrations When a workflow needs an app that's not connected, Catalyst shows cards with **Connect**, **Configure**, or **Reconfigure** actions. Complete setup using the card instead of pasting credentials in chat. See [Connecting external apps](/sections/documentation/catalyst/building-workflows#connecting-external-apps). Catalyst chat showing a Configure integrations card with a Connect action #### Questions Catalyst may ask clarifying questions with selectable options (single or multi-select). When you pick an option and submit, Catalyst will note your answer and resume working. Catalyst questions card with selectable options #### Temporary workflows Catalyst may create a temporary workflow to probe an API, fetch data, or validate an integration in the process of completing a task. When Catalyst proposes a temporary workflow, a card appears in chat showing: * The workflow name and a link to open it in the resource panel * **Run** and **Reject** actions (unless the workflow is read-only, in which case it may run automatically) Catalyst chat showing a temporary analysis workflow auto-approved as read-only and completed ### @Mention resources You can mention existing resources (such as workflows and Help Desk skills) when chatting with Catalyst. Type "**@**" to see a list of existing resources, and keep typing to specify. Catalyst composer with @ mention dropdown listing workflows and skills ### File attachments Attach files to Catalyst messages to share screenshots, data, or other context. * Click the **plus** in the composer to pick files * **Drag** files onto the chat area (a "Drop files to attach" overlay appears) * **Paste** files from your clipboard when supported by your browser #### Limits and supported types * **Maximum file size:** 50 MB per file (under 25 MB recommended) * **Maximum attachments:** 10 per message * **Supported file types:** * **Images**: PNG, JPEG, GIF, WebP * **Documents**: PDF, DOCX, XLSX, Visio (.vsd) * **Text**: CSV, TXT, Markdown, JSON ### Resource panel When Catalyst creates or opens a resource such as a workflow or skill, a tab appears in the **resource panel** on the right side of the chat. Edits made via chat or directly in the panel are not live until you publish or complete a review. Ticket labels also use this draft-and-publish flow. Click a label in the session resource list to open its resource tab and review its settings before publishing. The panel keeps up to 50 resource tabs open, with reports outside that limit. Opening another resource closes the leftmost inactive resource tab. Closing a tab keeps its resource and staged changes intact; reopen it from the session resource list when needed. Catalyst resource panel showing a draft Okta MFA reset workflow beside the chat *** ## Learn more What Catalyst can do Open your first session and publish a change Using Catalyst to analyze ServiceNow tickets and build automations Stage changes, propose reviews, and configure approvers Natural language prompting, manual edits, versioning Building analytics dashboards with Catalyst Teach Catalyst how to build your workflows Scheduled agents that surface findings for review *** ## Related links Instructions for the help desk agent on end-user requests Builder access and team capabilities Published versions and history for individual workflows # Changes and reviews Source: https://docs.serval.com/sections/documentation/catalyst/changes-and-reviews Propose changes for review, configure approvers, and publish to your team Catalyst requires users to expressly publish any changes to workflows, skills, and other resources. All updates made within a chat are grouped into a change set, which can be published directly or proposed for review depending on your team settings. *** ## Change sets A change set collects every resource Catalyst modified in a chat session: workflows, help desk skills, Catalyst skills, dashboards, and more. You can view the change set in the collapsible changes slip above the chat composer. Until you publish (or a review is approved and published), changes exist only as drafts tied to the chat session. ### Apply or reject a promotion Open a promotion from either the sending or receiving team to apply or reject it. **Apply promotion** and **Reject** both require configuration-transfer permission in the receiving team, which team managers have. Managing only the sending team doesn't grant either action. If you lack this permission, both buttons stay visible but disabled. Hover over a disabled button to see which receiving team requires permission. When a promotion doesn't require approval, **Review ready** notifications go to receiving-team members with configuration-transfer permission, excluding the requester. Open the review to inspect the changes before applying or rejecting them. Required approvals, CI checks, and user matches must still be complete before you can apply the promotion. While an apply attempt is running or has failed, the review shows **Apply attempted by** with the person's name. **Published by** identifies the person whose apply completed. Check the review status and resource results to see which changes reached the receiving team. Where workspace environments are enabled, the workspace's **Reviews** page remembers your promotion path, application status, author, and title search when you return from a review or reload the page. These filters are saved in your browser separately for each signed-in user and workspace. With **Test & Release** enabled, you can choose **Withdraw** on a promotion you proposed and confirm **Withdraw promotion**. The review moves to **Closed**. If no resource changes have been applied, its header shows **Withdrawn** even if an approval is still pending. The receiving team can't apply the withdrawn promotion. ### Review CI policy changes Catalyst can stage your team's Review CI settings as a portable resource. Where Review CI is enabled, choose **Open resource → Review CI policy** to view required workflows and evaluation suites. In a Catalyst session, you can stage changes to these checks and inspect additions and removals before proposing or publishing them. You can also open **Promotion checks** from **Test & Release → Reviews** or an environment or branch row on **Environments**. Promotion links open Reviews with promotions selected. The dialog identifies the team whose policy you're viewing. Users with permission to manage that team's SDLC settings can select checks and choose **Save checks**; users with settings-view permission can inspect the policy without editing it. Each CI attempt captures the checks it runs and their results. The review's check list links to the resulting workflow or evaluation-suite run so reviewers can inspect the evidence before publishing. Promotion workflow checks run in the source team before the promotion is applied. A target team's policy can require checks, but those workflows still execute in the source team. Resource lookups within a check use the team specified by the workflow; `ctx.currentTeam` refers to the source team. To investigate a failure, open the linked run and inspect its error rather than inferring the cause from the target team's configuration. For each selected evaluation suite, choose **Minimum pass** to set a whole-number percentage from **1% to 100%**, then choose **Apply** and save the policy. The default is **100%**. This threshold belongs to that suite's entry in the CI policy; workflow checks still have to pass individually. Suite CI waits for the run to finish and divides evaluations that met their expected result by **all evaluations in that run**. Missing scores count against the total. An empty suite or an execution error fails CI regardless of the percentage. The linked suite run shows this CI result separately from the **Scored evaluation pass rate**, which considers only scored evaluations. During a branch promotion, required checks come from the receiving team's current policy plus any CI policy included in the review. Unrelated checks in the source team's policy do not block the promotion. Checks run against the source team's published configuration, using the stricter minimum pass percentage when both policies require the same suite. Removing a selected check from the source team's live policy does not stop it from running for that review. Reviewers can inspect suite changes and percentage changes in the promotion diff. Removing a receiving-team requirement from the selected policy cannot bypass it; unavailable required workflows or evaluation suites still fail CI. The review's **Rerun all** action creates a fresh CI attempt and reruns the full required suites. Rerunning an individual evaluation separately does not update an earlier CI attempt's result. Each attempt retains the threshold used for that attempt. For branch promotions, **CI not started** means required checks haven't started; open the checks and choose **Start checks**. **CI rerun required** means the last attempt doesn't cover the current policy, and **CI blocked** means a required check failed. **Apply promotion** stays disabled until the required checks pass. If a required workflow or suite is missing from the source policy, use **Pull latest** to bring the parent's changes into the branch, apply that update, and choose **Rerun all** on the original review. Pulling the policy doesn't replace the original review's CI results. ### Publishing and discarding individual changes You don't have to publish an entire change set at once. When approval isn't required, you can publish or discard individual changes from the changes slip above the composer, or from a resource's own tab. Publishing a change also applies any drafts it depends on; discarding one also discards the drafts that depend on it, so the change set stays consistent. *** ## Direct publish vs review Which path you use depends on the Catalyst review approval settings. Team managers can open **Settings → Catalyst → Approval settings → Catalyst** to configure the policy. * If **Require approval before publishing** is off, users with Builder permissions or higher can directly publish changes drafted by Catalyst. * If **Require approval before publishing** is on, users with Builder permissions or higher must propose the change set for review. Designated approvers must sign off before anyone can publish. When approval is required, per-resource **Publish** buttons are hidden. Publishing happens only after a review is approved and someone clicks **Publish**. *** ## Team settings for reviews Managers can configure review behavior under **Settings → Catalyst** by clicking **Approval settings**. In the **Approval settings** dialog, select **Catalyst** to configure publishing approvals for Catalyst changes. ### Require approval before publishing When enabled: * Builders must propose change sets for review rather than publishing directly from the chat. * Configured approvers must approve or deny each review. * After approval, an authorized user clicks **Publish** on the review to apply the change set. When you require approval before publishing, configure at least one approver step, which can consist of users, groups, or special members like Team owners. Click **Save changes** after editing approvers. Leave approval off for small teams that trust every builder to publish. Turn it on when changes need a second pair of eyes before they go live. *** ## Propose for review When approval is required and you have pending changes: 1. **Finish staging changes**: Confirm every resource in the change set shows the state you expect. 2. **Click Propose for review**: In the collapsible bar above the composer, click **Propose for review**. 3. **Add title and description**: Enter a short title (required) and optional description explaining what changed and why. Click **Propose**. 4. **Notify reviewers**: The review appears in the **Reviews** view of the **Catalyst** page for teammates with access. They can inspect changes without opening your private chat (unless you shared it as a team chat). Each pending change set can have one review. Reviewers approve the change set as it stood when the review was created. If newer changes are saved in the same chat, the original review shows **Needs new review** and disables **Publish**. Choose **Go to Catalyst session**, then **Propose for review** to submit the latest changes for approval. *** ## Reviewer workflow Slack change set approval messages show the **Target environment**, so you can check where the changes will apply before approving. When email notifications are enabled, designated approvers receive a **Change set approval** email for Catalyst changes. The email includes the review title, a summary of up to 500 characters, requester, and resource count. Click **Open review** to read the full description, inspect the changes, and approve or deny them in Serval. 1. Open the **Catalyst** page from the sidebar and switch to the **Reviews** view. Reviews show a title, proposer, linked resources, and status. 2. Select a review to see title and description (editable by reviewers with access), Catalyst session link that opens the originating chat if you have access, per-resource diffs (workflow code changes, skill content, etc.) 3. Approve or deny the review When all required approvers have signed off, the review shows **Approved**. Someone with publish permissions can now click **Publish** on the review to apply the change set. *** ## After publishing * Resources show as **Published** in the originating chat session * Workflows appear in **Workflows**, skills in **Skills**, and dashboards in **Analytics** * The review status updates to **Published** If publishing or applying a promotion fails, select the failed resource in the review. Its error message identifies the resource, explains the cause when known, and suggests a next step. For example, invalid workflow code requires a correction and an updated change; a temporary service failure can be retried later. If a simulation config's name is already used in the receiving team, rename the incoming config or resolve the existing config before submitting an updated change. Failure guidance is currently shown in English. Older failures without readable guidance show a support fallback. If a workflow references a custom app that can't be resolved in the target team, connect the required custom app in **Integrations** and retry the failed change. If the workflow's `HttpIntegration` alias is incorrect, correct it to match a configured app and submit an updated change. The review keeps successfully applied changes separate from failed changes. Follow the failed resource's guidance before retrying. For an unknown failure, choose **Copy support reference** and include the reference when you contact support. You can also ask Catalyst in the originating chat to inspect the latest publish results and identify failed resources and their dependencies. A successful simulation run doesn't establish that other draft changes published. Check the remaining drafts before discarding them. *** ## Read reviews through the API Use the read-only `/v2/reviews` API to inspect an existing review from an integration or approval workflow. It supports reviews from Catalyst sessions, background-agent sessions, and promotions. 1. Call `GET /v2/reviews?teamId=TEAM_ID` to find reviews owned by a team. Use `outgoing=true` to list promotions from that team. 2. Call `GET /v2/reviews/REVIEW_ID` for the source and target organizations and teams, session context, current approval status, and change-set apply status. `origin` is `REVIEW_ORIGIN_CATALYST` for session-owned reviews (including background-agent sessions) or `REVIEW_ORIGIN_PROMOTION` for config pushes. If a source or target team has been deleted, its organization ID is omitted. 3. Call `GET /v2/reviews/REVIEW_ID/items` for item metadata. Pass `nextPageToken` back as `page_token` until it is empty. Both list endpoints default to 50 results and accept a `page_size` up to 100. 4. Call `POST /v2/reviews/REVIEW_ID/items:batchGet` with `{"itemIds":["ITEM_ID", "OTHER_ITEM_ID"]}` for up to 20 unique items' `before` and `after` resource documents. Results follow request order; a missing item or an item from another review fails the entire request. You can also read one item with `GET /v2/reviews/REVIEW_ID/items/ITEM_ID`. Creates have no `before` document; deletes have no `after` document. Updates merge the proposed patch onto the comparison's before state. The documents use the same backend comparison behavior as the review UI. Pending updates and deletions may use live resource data, so later edits can change the comparison. Pagination doesn't freeze the review. Documents use the portable review format, not the public API's create or update request format. Recognized credential patterns are redacted. If `contentStatus` is `REVIEW_ITEM_CONTENT_STATUS_MISSING_BASE` or `REVIEW_ITEM_CONTENT_STATUS_UNSUPPORTED`, stop automated approval and send the item for manual inspection. Each item's `resourceKind` uses the backend's canonical kind, such as `workflow` or `skill`. Its `applyResult` contains exactly one outcome: `pending: {}`, `applied: {}`, or `failed: {"reason": "…"}`. This is the result of applying the staged change, not the resource's runtime status. Failure reasons are redacted. `contentStatus` separately describes whether its comparison documents are available; an applied item can still have unavailable documents. Scoped API keys need **Read reviews** (`reviews:read`) and access to the source or target team. A workflow in either team can read the promotion's details, items, and comparison documents. Session reviews require access to the session's team. Cross-organization programmatic reads aren't supported. `approval.status`, `approval.required`, `review.applyStatus`, and `review.closedAt` describe separate states. An approved review is not necessarily published. These endpoints don't create, approve, close, or publish reviews. ### Read a review in an approval workflow Get the review ID from the approval context and call the public API with `serval.apiRequest`. It uses the workflow's authenticated connection and existing retry handling. ```typescript theme={null} const reviewId = serval.context.getChangeSetReviewForApproval(ctx)?.subjectId; if (!reviewId) throw new Error("This approval step has no configuration review"); const response = await serval.apiRequest( { method: "GET", path: "/v2/reviews/{review_id}", pathParams: { review_id: reviewId }, }, ctx, ); const review = response.data; ``` Use the item-list and batch-read endpoints above to inspect every page of changes. Your workflow decides how to route approval and handles missing or unsupported content. Reading a review doesn't approve or publish it. ### Ask Catalyst to inspect a review In a team workspace, give Catalyst a review link, ID, or title and ask it to identify behavioral risks. The review-reading skill isn't available in personal workspaces. Catalyst finds the review, reads its item pages, and fetches before/after documents in batches. It reports what it inspected, any unavailable content, and questions a human should resolve before approving. Review text and code are treated as untrusted content. Catalyst respects access restrictions and does not approve or publish the review. Continue in **Reviews** to make the human decision. ## Related What Catalyst can do Get familiar with the Catalyst interface Open your first session and publish a change Using Catalyst to analyze ServiceNow tickets and build automations Natural language prompting, manual edits, versioning Building analytics dashboards with Catalyst # Configure access management Source: https://docs.serval.com/sections/documentation/catalyst/configuring-access-management Use Catalyst to automate access requests by configuring roles, profiles, policies, and provisioning Catalyst can configure Serval's [access management](/sections/access-management/overview) from a plain-language description: the roles employees can request, whether requests need approval, how long access lasts, and how access is actually granted. Catalyst drafts everything for you to review and publish, so nothing goes live until you approve it. ## What Catalyst can configure * **Set up an app for access requests**: create the roles employees can request on an app or a specific resource inside it (a Slack channel, GitHub repo, AWS database, and more). If the app isn't connected in Serval yet, Catalyst can create it too (native or custom), so access setup works end to end in one session. * **Access profiles**: control which users or groups can request access to a role in the Help Desk. * **Access policies**: configure approvals, max access length, and business justification for a role. * **Provisioning**: how access is granted, whether by a linked identity-provider group, a manual task assigned to a person or group, or a custom workflow. ## How it works Describe what you want in a Catalyst session. Catalyst identifies the app, the resource, and the roles involved (creating the app in Serval if it isn't connected yet), then drafts the roles, policies, and profiles as items in the side panel. Review the drafted items and click **Publish** to make them live. Nothing changes until you publish. For information on how staging and publishing work, see [Changes and reviews](/sections/documentation/catalyst/changes-and-reviews). A Catalyst session with drafted access roles and an access policy open in the side panel, showing the Publish action ## Example tiered access flow A single prompt can set up a full access flow, including creating the app in Serval if it isn't connected yet. Consider the following example prompt: > Set up access management for Figma. Employees should be able to request Editor or Admin. Editor is self-serve, no approval. Admin requests need my approval, and access should expire after 30 days. Provision both roles from our Okta groups: `figma-editors` for Editor and `figma-admins` for Admin. From that description, Catalyst drafts three items: * An **Editor** role: self-serve with no approval, provisioned through the `figma-editors` Okta group. * An **Admin** role: gated by an access policy, with access that expires after 30 days, provisioned through the `figma-admins` Okta group. * A **Figma Admin Approval** access policy: a 30-day access duration with you as the single approver. Review the three items in the side panel and click **Publish**. You can publish the whole change set at once, or use the **Publish** button on an individual resource's tab to publish just that item. If it depends on other staged items, Catalyst publishes those alongside it. The result is a tiered flow: Editor is instant and self-serve, while Admin requires your approval and expires automatically after 30 days. Both roles provision automatically through their linked Okta groups, so each grant is a single membership change you can audit. ## Provisioning methods When Catalyst sets up a role, it configures how access is actually granted. A role can't grant access until it has a provisioning method: * **Linked group**: the grant maps to an IdP group (Okta, Microsoft Entra, Google Workspace). Prefer this when possible, since it makes each grant a single membership change you can audit, with no custom workflow to maintain. * **Manual**: a person or group grants access by hand. * **Custom workflow**: a workflow provisions and deprovisions access for systems that need bespoke API calls. ## Usage tips * **Access profiles grant request eligibility, not automatic access.** A profile controls which roles a group is allowed to request in the Help Desk. It doesn't assign those roles to group members automatically. * **Changes are drafted, then published.** Catalyst stages access changes for review. Click **Publish** to apply them. Nothing is live until you do. ## Related Roles, access policies, provisioning, and the full access lifecycle. How Catalyst stages changes and how you review and publish them. Build the workflows that access requests and provisioning rely on. # Building dashboards Source: https://docs.serval.com/sections/documentation/catalyst/dashboards Building analytics dashboards with Catalyst Catalyst can build analytics dashboards for your team directly from natural language. When you describe what you want to see, Catalyst will: * Design the widgets * Run them against your data * Stage the dashboard as a draft you can review *** ## What Catalyst can build An analytics dashboard is a collection of widgets arranged on a grid, backed by workflows that query your data. This can include Serval data (like tickets, access requests, assets, and workflow runs), as well as any data from connected apps (like ServiceNow or GitHub data) or public APIs. Catalyst can author dashboards with any combination of: * **Charts**: bar, line, area, and pie charts * **Tables**: row-level views, top-N lists, detail grids * **Stats**: single-number KPIs (counts, averages, sums) with trend indicators and sparklines * **Text**: section headers and inline commentary * **iFrame**: embeds of external content (only certain sites that explicitly support embedding) * **JSON**: raw structured output, useful for debugging Charts, tables, stats, and JSON widgets require a workflow connection. Text and iFrame widgets can display static content without one. Widgets can share workflows when they read the same dataset (for example, a stat and a table both summarizing the same query), which keeps the dashboard lean. *** ## Tips for better dashboards Catalyst handles dashboards best when you give it three things up front: * **Purpose**: What question the dashboard answers ("ticket triage health", "access request volume by team", "device fleet status"). * **Time range:** The default window for the data ("last 30 days", "this quarter", "year to date"). * **The widgets you have in mind**: A rough sketch is enough ("a count, a trend chart, and a breakdown by priority"). If your request is ambiguous, Catalyst will ask a couple of targeted clarifying questions before building. For comparison colors, describe what improvement means: lower response time, higher availability, or no preferred direction for a metric such as request volume. You can also request specific series colors. See [Chart colors and stat comparisons](/sections/documentation/platform/analytics#chart-colors) for how these choices appear on the dashboard. ### Example prompts * "Build me a dashboard for ticket triage over the last 30 days. Total open tickets, a trend chart, top assignees, and a breakdown by priority." * "Access requests by app (Figma, GitHub, AWS, Salesforce, Ramp) with approval times and denial rates." * "CrowdStrike detections and Qualys vulnerabilities by severity, trended weekly." * "Offboarding SLA dashboard: time from Workday termination to Okta deactivation and license reclaim." *** ## Time-range variables Most dashboards include a time-range variable so the whole dashboard can be scoped to a window from a single control. Catalyst wires this up automatically when you mention a time range in your request, and uses the range you specified as the default. After publishing, you can change the range from the dashboard controls without re-running Catalyst. To choose specific dates, open the time-range control and select **Custom…**. Choose **From** and **To** dates in the calendars, then select **Apply** in the side panel. Both dates use UTC; changes stay in the panel until you apply them. When the selected range differs from the saved default, **Temporary view** appears beside the time-range control. Select **Reset** to return to the saved range, or **Set as default** to save the current range for the dashboard. Setting a default requires edit permission. You can switch to **Editing** while keeping a temporary range; switching modes does not save it as the default. If you'd rather lock a widget to a specific data slice (for example, a "Q1 results" widget that shouldn't move with the dashboard's time control), say so explicitly, and Catalyst will use concrete values for that widget instead of wiring it to the variable. *** ## The build process When Catalyst builds a dashboard, you'll see activity in three phases: * **Register the dashboard.** Catalyst commits the dashboard's name, time-range variables, and an empty layout. The dashboard appears as a draft in the side panel immediately. * **Build each widget.** For every widget on the plan, Catalyst writes a workflow, runs it against your data, optionally previews the widget inline in chat so you can confirm it looks right, then attaches it to the dashboard. * **Finalize the layout.** Once every widget is built, Catalyst arranges them on the grid and updates the dashboard with the final layout. Throughout the build, you can view and explore the draft dashboard. After Catalyst builds the initial version of the dashboard, you can continue to chat with Catalyst to iterate on dashboards before publishing. Catalyst checks required workflow connections when creating or updating a dashboard draft. If a widget is missing its required connection, the change is rejected so Catalyst can correct it before it reaches review. ### Sharing workflows across widgets Catalyst is deliberate about workflow reuse. If two widgets read the same dataset (for example, a count and a table both summarizing tickets by priority over the same window), they'll share a single workflow. This makes the dashboard easier to maintain and faster to refresh. When widgets read genuinely different data (different time windows, different fields), Catalyst writes separate workflows. *** ## Editing a dashboard Catalyst can edit dashboards you've already published. Common edits include: * **Add a widget**: "Add a stat showing total resolved tickets to my triage dashboard." * **Edit a widget in place**: "Change the trend chart to weekly buckets instead of daily." * **Remove a widget**: "Drop the assignees table from the triage dashboard." * **Rename or re-describe the dashboard.** * **Change the time-range variable**: "Default to last 90 days instead of last 30." Simply @mention the dashboard and Catalyst will find it. Edits are staged in the resource panel in the same way a brand new dashboard does, and **Publish** applies the changes to the live dashboard. ### Removing widgets Removing a widget is an explicit action. If you want a widget removed, you must explicitly ask Catalyst to remove it. ### Iterating on a widget If a widget doesn't look right (wrong chart type, wrong columns, wrong grouping), tell Catalyst what to change. It will update and re-render the preview so you can confirm the new format before publishing. *** ## Reviewing and publishing When Catalyst finishes, you'll have a dashboard draft in the resource panel. From there you can: * Open the dashboard preview to confirm the widgets render correctly and the layout reads well. * Open any individual widget to inspect its workflow and configuration. * Click **Publish** to save the dashboard. Widget workflows are scoped for dashboard rendering only and are not exposed to the help desk agent. ### Refresh dashboard data On a published dashboard, open **Data Sources** from the dropdown beside the refresh control. Search by workflow name to narrow the list, or select a source to open its workflow. Select **Refresh all** at the bottom to refresh the dashboard’s data sources, including sources hidden by your search. In a temporary view, refresh uses the selected time range without changing the saved default. *** ## Related What Catalyst can do Get familiar with the Catalyst interface Open your first session and publish a change Using Catalyst to analyze ServiceNow tickets and build automations Stage changes, propose reviews, and configure approvers Natural language prompting, manual edits, versioning # Getting started with Catalyst Source: https://docs.serval.com/sections/documentation/catalyst/getting-started Start your first Catalyst session and publish your first workflow This guide walks you through your first working Catalyst session. *** ## Prerequisites Catalyst is on by default. To publish workflows, you need **Builder** permissions or higher. *** ## Configure defaults (optional) **Catalyst** appears in the team sidebar, at the top of the group with **Workflows**, **Skills**, and **Background Agents**. As a Manager, you can set the default chat mode and whether publishing requires review under **Settings → Catalyst**. See [Changes and reviews](/sections/documentation/catalyst/changes-and-reviews#team-settings-for-reviews). *** ## Start your first session Click **Catalyst** in the sidebar. You land on the chat view with a new-session composer. Before sending a message, set **Team chat** or **Private chat** (who can see this session) and **Fast** or **Thinking** (speed vs depth for the agent's reasoning). Send a concrete prompt, for example: "Create a workflow that adds a user to the "all-staff" Slack channel when they're onboarded. Search installable workflows first before writing new code." Click **Quickstart** above the chat window for common first steps, or **Browse prompts** for more example requests. Inspect the workflow summary and the code if desired. Ask follow-up questions in chat or edit the code directly in the resource panel. After you create a workflow, Catalyst asks if you want to test it. If your team allows direct publishing, click **Publish** on the workflow tab or above the chat composer. If your team requires review before publishing, click **Propose for review** above the chat composer. See [Changes and reviews](/sections/documentation/catalyst/changes-and-reviews). Once published, your workflow appears in **Workflows**. Configure [triggers](/sections/documentation/workflows/Run/triggers), check [run history](/sections/documentation/workflows/Run/run-history), and debug from Catalyst as needed. *** ## Related topics What Catalyst can do Get familiar with the Catalyst interface Using Catalyst to analyze ServiceNow tickets and build automations Stage changes, propose reviews, and configure approvers Natural language prompting, manual edits, versioning Building analytics dashboards with Catalyst # Building journeys Source: https://docs.serval.com/sections/documentation/catalyst/journeys Creating multi-threaded journeys using Catalyst A journey is a multi-step, structured process in Serval that coordinates many tasks across many people, in the right order, over days or weeks. Journeys are used most often for onboarding and offboarding, but can be useful anywhere a process spans multiple people or systems. Catalyst can design and build these journeys for you through natural language or with an uploaded flowchart. To learn more about journeys, see [Journeys](/sections/documentation/journeys/overview). *** ## What journeys don't do Journeys don't directly control access provisioning (adding users to IdP groups, granting app roles, assigning licenses). You can set a journey to *trigger* access requests and track the completion in tasks, but you will need to handle the access logic itself in [**Access Management**](/sections/access-management/overview). *** ## Cross-team journeys Journeys frequently cross team boundaries. IT, HR, Security, and Finance each own pieces of onboarding. Catalyst handles this natively: tell it which team owns each task and it will route assignments accordingly. Each team sees only their tasks in their queue, while the journey as a whole tracks end-to-end completion. You can include workflows and automations from other teams to attach to tasks. For information on how cross-team journeys appear to admins and end users, see [Cross-team journeys](/sections/documentation/journeys/cross-team). *** ## Create a journey in Catalyst ### Use natural language instructions Open a Catalyst chat and describe the journey in plain language. The more concrete you are about *who does what, in what order*, the less Catalyst has to ask back. A useful prompt covers: 1. **The trigger**: What kicks the journey off (a form submission, a date, an event in your HRIS) 2. **The tasks**: The discrete steps, in order 3. **The owners**: Which team or role handles each task 4. **The dependencies**: Which tasks must wait for others For example: > "Build me an onboarding journey for new engineers. When there's a new-hire event in Workday, IT should create an Okta account and order a laptop in parallel. Once the account exists, HR runs a background check and the hiring manager gets a task to prepare a welcome doc. The new hire's first-day checklist task only opens after the background check is complete." ### Use a flow chart diagram You can also upload a flow chart diagram. For a list of file formats, see [File Attachments](/sections/documentation/catalyst/catalyst-workspace#file-attachments). Catalyst will read the diagram and create a journey based on the chart. As with a text description, the more concrete information you include, the fewer follow-up questions Catalyst needs. You can upload a flow chart to start and then use natural language prompts to iterate. ## Attaching workflows to tasks Each task or subtask can optionally have an attached workflow that runs automatically or after collecting inputs from the employee. If the workflow requires inputs, the journey task shows a form to collect them and runs the workflow once the assignee fills it out. Tell Catalyst to attach a published workflow to a task by @-mentioning it in the prompt, or describe a new workflow for Catalyst to build, publish, and attach. For example: > "Attach the @Create Okta account workflow to the 'Set up accounts' task, and run it when the task starts, using the new hire's email from the journey." For more information about tasks and attached workflows, see [Journey tasks](/sections/documentation/journeys/tasks). ## Live journey preview Your draft is immediately testable in the Catalyst chat. You can run it on yourself or a test user without publishing first. If a task is assigned to the wrong group, a dependency is backwards, or you want to split a step into subtasks, just tell Catalyst in the same chat and it will update the draft in place. When you build a journey with Catalyst and initiate a test run, Catalyst's run-details panel automatically switches into a **live journey preview**. The preview shows the overall layout of the full journey page, with tasks organized in columns by assignee. For more information on tasks and task states, see [Journey tasks](/sections/documentation/journeys/tasks). ## Publishing When the journey looks right, click **Publish** in the side panel. That exposes it to the help desk agent and any external triggers (scheduled runs, webhooks, HRIS events) so it can run for real employees. ## Use databases to save journey state A journey often needs to carry state across its tasks. For example, in an employee onboarding journey, an account ID created in an earlier task is needed by a later task once a background check clears. [Serval databases](/sections/documentation/databases/overview) store that state and let you reference it from tasks and tickets throughout the journey. You don't have to build this manually. When you build the journey in Catalyst, describe the state you want to keep. Catalyst gives each journey type its own entity type in a Serval database (for example, `onboarding-journey-state`), keyed by the journey ticket ID so each journey has exactly one row, and sets up the steps that read and write it. ## Tips for working with Catalyst on journeys * **Name tasks the way employees will read them.** "Sign offer letter" beats "Execute employment agreement workflow." * **Be explicit about parallelism.** Specify if two tasks can happen at the same time. Otherwise, Catalyst may chain them sequentially. * **Mention reminders and SLAs.** If a task should escalate after 2 days, tell Catalyst up front rather than bolting it on later. * **Test before publishing.** Run the draft against yourself or a test user to walk through the task assignments and dependencies in a real ticket queue. * **Ask for a flow chart diagram with dependencies.** As you're building a journey, you can ask Catalyst to show you the journey as a flow chart diagram with dependencies. Catalyst will create a visual diagram you can inspect and use. Open the diagram fullscreen to zoom and pan. Diagrams display as images; embedded links and external images are inactive. * **Use manual tasks for tasks without attached workflows.** Manual tasks have no attached workflow. The assignee completes the task on their own and finishes it by clicking **Mark complete.** ## Troubleshooting ### Why are tasks not showing up in the columns I expect? If a task isn't in the column you'd expect, check its assignee. Journeys group tasks into columns by assignee: * Any task assigned to the requester (for example, the new hire) shows up in the requester column. * Any task assigned to a member of a Serval team shows up under the column for that team. * Any task assigned to a user who isn't the requester or a member of a Serval team shows up in the stakeholder column. ### Why are certain automation tasks not automatically firing? This normally means the workflow still requires inputs, or the workflow is set with **Use a form to collect inputs.** If you want to auto-run an attached workflow that requires inputs, tell Catalyst to auto-submit inputs with hardcoded values or variables from the journey, like the new hire's email. ### Why are some journey tasks showing up in a team column but others aren't? A team column shows tasks that are assigned to a member of that team and hides the rest. If a task you expected to see is missing, check its assignee. ## Related What Catalyst can and can't do Get familiar with the Catalyst interface Stage changes, propose reviews, and configure approvers Natural language prompting, manual edits, versioning Coordinate multi-step, cross-team processes # Catalyst overview Source: https://docs.serval.com/sections/documentation/catalyst/overview Serval's automation agent for building workflows, skills, dashboards, and more **Catalyst** is an admin-facing agent that can create and edit workflows, skills, dashboards, journeys, and more. It can also analyze data, generate reports, and proactively investigate issues in your environment. Catalyst is how you build and publish workflows and skills. Workflows themselves are unchanged: they still run on triggers, appear in run history, and integrate with the help desk. *** ## How it works Simply start a chat with Catalyst and describe what you want to automate. When Catalyst creates or updates a workflow, skill, or dashboard, the draft appears in the resource side panel for you to review. You can view, test, and iterate on drafts end-to-end before publishing. When you're ready to use the resource you created, click **Publish** or **Propose for review**, depending on your Catalyst settings. *** ## What Catalyst can do ### Build workflows Catalyst authors Serval workflows, the deterministic automations that power your help desk. Reset passwords, onboard new hires, sync data between systems, post to Slack on a schedule, and more. Describe the outcome and Catalyst drafts the workflow for you to review and publish. ### Author skills Skills shape how the help desk agent behaves: tone, escalation paths, troubleshooting flows, and when to invoke specific workflows. Catalyst drafts skills from your description including both the "when to use it" and "what to do." ### Create journeys Journeys are multi-step workflows, most often used for onboarding/offboarding, that coordinate tasks and dependencies across teams. Catalyst can build and edit journeys for you through natural language. ### Configure access management Catalyst sets up access requests based on details like the roles employees can request, whether requests need approval, how long access lasts, and how access is provisioned. It drafts the roles, policies, and profiles for you to review and publish. For more information, see [Configuring access management](/sections/documentation/catalyst/configuring-access-management). ### Build dashboards Catalyst can build [analytics dashboards](/sections/documentation/catalyst/dashboards) against any data from Serval, connected apps, and public APIs. Each dashboard widget is powered by a workflow that Catalyst writes for you. ### Investigate issues and send reports Need to know which Okta groups are empty, which tickets are stuck, or what's in your knowledge base? Catalyst can run complex queries, return answers directly in chat, and email a report. ### Debug workflow runs When inspecting any workflow run, hit "Investigate in Catalyst" to analyze what happened. This enables your team to debug failed or stalled workflow runs. Catalyst keeps gaining new capabilities, so you may find it can do more than what's listed here. *** ## Learn more Get familiar with the Catalyst interface Open your first session and publish a change Using Catalyst to analyze ServiceNow tickets and build automations Stage changes, propose reviews, and configure approvers Natural language prompting, manual edits, versioning Building analytics dashboards with Catalyst Set up roles, approvals, and provisioning with Catalyst *** ## Related topics For roles, approval policies, and provisioning rules. Configure who has access to what resources. How workflows run, trigger, and integrate after you build them in Catalyst Instructions for the help desk agent on end-user requests Builder access and team capabilities Published versions and history for individual workflows # Tutorial: Build automations from ticket history Source: https://docs.serval.com/sections/documentation/catalyst/tutorial Using Catalyst to analyze ServiceNow tickets and build automations In this tutorial, you'll use Catalyst to mine your ServiceNow ticket history for patterns and turn the top automation candidates into working Serval workflows and skills. If you don't use ServiceNow, you can replicate this tutorial with Serval ticket history or a different ITSM such as Jira Service Management or FreshService. Due to the probabilistic nature of LLMs, you may see different responses from what's listed below. Follow up with refined requests as needed while following these steps. **Time required:** \~30 minutes\ **You'll need:** A Serval team with ServiceNow connected, and Manager or Builder permissions on that team. *** ## What you'll build * A read-only investigation that pulls recent ServiceNow tickets and groups them by category. * A Serval workflow that automates the most common request type Catalyst surfaces. *** ## Step 1: Connect ServiceNow (if you haven't already) Open Catalyst from the side panel in Serval and ask: *"Is ServiceNow connected to this team?"* If it isn't, Catalyst will surface a Connect card. Click through the integration flow and return to the chat. Catalyst will pick up where you left off. *** ## Step 2: Ask Catalyst to analyze your ticket history In the chat, describe what you want to accomplish: *"Pull the last 90 days of ServiceNow incidents for our team. Group them by category and show me the top 10 most common request types, with counts and example tickets."* Catalyst will: * Draft a temporary read-only investigation that queries ServiceNow's incident table. * Run it immediately (read-only investigations auto-approve). * Return a summarized table directly in chat. You'll see something like this: | Category | Count | Example | | :-: | :-: | :-: | | Password reset | 187 | INC0012345 | | New laptop request | 94 | INC0012402 | | VPN access | 71 | INC0012498 | | … | … | … | *** ## Step 3: Pick an automation candidate Look at the results and pick the highest-volume request that's also the most mechanical. In this example, **password reset** at 187 tickets in 90 days is the obvious starting point. Ask Catalyst: *"Can you build a workflow that resets a user's password in Okta and notifies them in Slack?"* Catalyst will: * Check whether a password reset workflow already exists in the team * Confirm which integrations to use (Okta for the reset, Slack for the DM) * Draft the workflow and stage it in the resource side panel You'll see the draft appear alongside the chat with the full TypeScript visible for review. *** ## Step 4: Test the workflow before publishing You can run draft workflows immediately inside Catalyst before publishing. Catalyst may prompt you to do so, or you can click **Run** in the resource panel. We recommend testing the workflow against a dummy user account. To make adjustments to the workflow, describe the update in chat and Catalyst will edit the draft. *"Update the Slack message to include a link to our password manager at passwords.example.com."* *** ## Step 5: Publish When the draft workflow looks right, click **Publish** in the resource panel. Publishing exposes it to: * The help desk agent (so it can run on incoming requests from Slack, Teams, email, or web) * External triggers (scheduled runs, events, webhooks, API calls) Until you publish, the changes only exist inside your Catalyst session, without affecting live tickets. *** ## Tips * **Start narrow.** "Reset password in Okta" is a better first workflow than "handle all account problems." Small, focused workflows are easier to test and reuse. * **Let Catalyst search first.** Before building, Catalyst checks for existing workflows and the installable gallery. * **Access provisioning isn't a workflow.** If your analysis surfaces "grant access to X" requests, configure those in **Access Management**, not as a standalone workflow. Catalyst will guide you there. *** ## What's next * Connect more sources (Jira, Zendesk, your existing knowledge base) so Catalyst can analyze across systems. * Use Catalyst to build an analytics dashboard tracking how often each new workflow runs and how many tickets it deflects. * Set up a background agent to re-run the analysis monthly and surface new automation candidates as your ticket mix shifts. *** ## Related links What Catalyst can do Get familiar with the Catalyst interface Open your first session and publish a change Stage changes, propose reviews, and configure approvers Natural language prompting, manual edits, versioning Building analytics dashboards with Catalyst # Data flow diagrams Source: https://docs.serval.com/sections/documentation/data-flow-diagrams ## End-to-end flows between Serval and Customer applications The diagram below highlights system boundaries, data transmission paths, and key security controls within Serval. Hover over a component to isolate its flows, or over a line to trace it. Customer applications are provided as examples only — Serval can be connected with as many or as few external applications as needed. View full screen ↗ ## Hybrid self-hosted deployments In a [Hybrid Self-Hosted](/sections/self-hosting/hybrid) deployment the Credential Proxy runs alongside the Serval worker inside your own infrastructure. Integration credentials are stored encrypted in Serval Cloud by default; the proxy fetches them at call time, injects them into the outgoing request, and sends that request to the target service from inside your network. Workflow code never sees them. A connection configured with [worker-local credentials](/sections/self-hosting/deployment/worker-local-integrations) instead reads its credential from a Kubernetes Secret in your cluster, and Serval Cloud holds only a placeholder. The worker opens an outbound HTTPS connection to Serval Cloud; the workflow engine sends it signed integration requests and the result flows back. Everything else — the web app, the workflow engine, inbound webhooks, and application storage — stays in Serval Cloud. View full screen ↗ # Administration Source: https://docs.serval.com/sections/documentation/databases/administration Permissions, change history and provenance, and safe deletion ## Permissions Access to items follows two layers: the team role of the user, and the Help Desk Agent visibility of each item type. ### Team roles Every team role grants a specific level of access to item data: | Role | Can do | | :- | :- | | **Viewer** | Read items and their history. No edits. | | **Agent** | Read items relevant to assigned tickets (resolves to requester-associated items by default). | | **Contributor** | Read item field values. Can't edit field values or change the schema. | | **Builder** | Everything Contributor does, plus create, edit, archive, and delete items and item types. Can configure ingestions. | | **Manager** | Everything above, plus share item schemas to other teams. | See [Team roles and permissions](/sections/documentation/platform/permissions) for the full matrix across all platform resources. ### Help Desk Agent visibility Team-role access doesn't automatically grant access to the Help Desk Agent. Each item type has its own visibility setting that decides what the agent can read at runtime: | Setting | What the agent sees | | :- | :- | | **None** | Nothing. The agent can't query this type. | | **Requester associated** (default) | Only items linked to the requester. | | **Always** | Every item of this type. | Set **None** for sensitive types (compensation, security audit logs) that should never reach the agent, even if a Builder has otherwise granted broad access. Set **Always** for catalog and reference data the agent might need across requests. ### Table and field access A table or field can narrow the audience it gets from the database above it, but never widen it. Open a table's access from the access badge in its header (**Everyone**, **Write restricted**, or **Restricted**), or a field's access from **Edit field permissions** in the field's actions menu. When the database is shared with specific teams rather than the entire organization, select **Add teams, roles, or people** to limit the table or field to a role, group, or person. These rows show **Only if they also have access above**: they reach the table only if the database already gives them access. For example, to let only the Security Lead role inside Corporate IT see and edit a table: 1. Open the table's access. 2. Select **Add teams, roles, or people** and pick the **Security Lead** role. 3. Set the role to **Can write**. 4. Set **Corporate IT** to **No access**. Members of Corporate IT who hold Security Lead can read and edit the table. The rest of Corporate IT can't see it. A role, group, or person added this way can only get **Can write** if someone above them already has write access. ### Record-level access rules Beyond the type-wide audience, a manager can restrict a single record. Open the record and select the **lock** icon in its header to narrow who can read or write that row below the item type's audience. People without access see the record as a **Restricted record** placeholder with a lock instead of its field values, and its detail page explains that a manager of the database can grant access. Filtered lists note when restricted records can't be included in the results. ### Editing items from workflows Workflows run with the permissions of their owning team. A workflow exposed to the Help Desk effectively gives end users access to whatever it touches. A workflow can read and write any item in its team regardless of the calling user's role. Audit any workflow that writes to a sensitive item type before publishing. ## History and provenance When a field value changes, Serval records the change in field value history. Each change creates a new history entry; the prior value is kept as a deleted row. History captures: * **What changed.** The field, the new value, and (by comparing earlier entries for the same field) the previous value. * **Who changed it.** A user (manual edits via UI or API), or an ingestion source (shown as the connected app instance). Workflow runs aren't recorded on individual field history entries. * **When.** Timestamp of the write. Unchanged rewrites don't create new history entries. History is per field, retained indefinitely, and queryable in the item activity tab and via the API (`ListEntityFieldValueHistory`). ### Reading history in the UI Open any item and click **Field History** in the side panel. Each row is one change to one field. Filter by field to trace a single value's lineage, or by author to see what a workflow has been writing. ### Reading history from workflows You can build workflows to read field history programmatically. The common use cases: * **Alert on field change.** A scheduled workflow reads recent history for an item and notifies users when it changes. * **Debug a stale value.** Walk back through history to see which source last wrote the field and when. Useful when a sync isn't refreshing what you expected. * **Provenance reports.** List every value on a sensitive field along with its source, for compliance audits. ### Provenance and source of truth Each value carries the identity of whoever wrote it. For fields with multiple ingestion mappings, history shows which source won at each write. This is the audit-grade answer to "where did this number come from?" for finance and compliance teams. ## Archiving and deletion Removing an item has two lifecycles: **archive** (reversible) and **delete** (permanent). **Archive** hides an item from the default list and per-type counts while keeping it intact: it stays loadable by ID or key, still resolves when referenced, and keeps its key reserved. Use the **Show archived** toggle on the list to see archived items and **Unarchive** to restore one. In references, an archived item shows muted and labeled **(archived)**; a deleted item shows struck through and labeled **(deleted)**. **Delete** removes an item permanently: there's no restore, and its key is freed for reuse (change history is still retained for audit). Prefer archive when you might need the item back. If the item is fed by an ingestion config, disable the source mapping or change the source data, or the next sync recreates it. ### Delete items in bulk To remove every item matching a filter, use a workflow that searches and deletes. The list view doesn't expose bulk delete by default, to avoid accidents. ### Delete missing items vs. manual deletions The **Delete missing items** toggle on an ingestion config controls whether deletions at the source cause Serval to delete the corresponding item. Hand-deleting an item is independent of this: it removes the item from Serval, regardless of whether the source still has it. See [Ingestion](/sections/documentation/databases/ingestion#deletions). ### Delete an item type Deleting an item type also deletes all of its child types. The items themselves aren't permanently removed. Instead, they stay hidden from queries, but are kept for audit. You can't recover a deleted item type through the API. Before deleting an item type, check for: * Any workflow that reads or writes it. The workflow will fail on its next run. * Any skill that references it. The agent will fail to resolve the reference. * Any custom ticket field or catalog item that uses it as the reference target. * Any other item type with reference fields pointing at it. See [Schema design](/sections/documentation/databases/schema-design#deleting-an-item-type). ### Delete a field Removes the field from the type and by default from every descendant that inherits it. ## What's next The full role matrix across all platform resources. Configure what the Help Desk Agent can read. Add, evolve, and delete item types and fields. How deletions propagate from external sources. # Browsing and querying Source: https://docs.serval.com/sections/documentation/databases/browsing-and-querying List view, filters, saved views, and the context graph The list view shows every item of a type in a sortable, filterable grid. The context graph visualizes the relationships between items and lets you traverse them. Most day-to-day work happens in the list view. The context graph comes out when you need to understand impact, ownership, or dependencies. ## The list view List view for a MacBooks item type showing source, name, and key columns with search and filter controls Open any item type in the Databases tab to see its list view. By default, the columns are the key field, the name field, and a handful of others Serval picks based on the type. In the list view, you can: * Click **Columns** to pick which fields show * Filter on any column * Click on a column to sort ascending or descending * Search in the search box * Move between pages (500 items per page by default) * Save and share views * Set a default view ## The context graph Click any item on its detail view to see its context graph. Context graph for a virtual network item showing connected nodes and directional edges alongside the item's field detail The context graph visualizes the item reference fields you set up in [Schema design](/sections/documentation/databases/schema-design#item-reference-field) as a navigable network. Every item is a node. Every reference field, and every relationship type, is a directional edge. ### A person's items A user's profile has an **Items** tab that works like a database dashboard scoped to that person. The **Tables** pane on the left lists every table whose items reference the user through a user reference field, grouped by database, with the field name and the number of items under each table. * **Graph**: the first row opens the user's context graph across every table. A table with more than a handful of references collapses into a footer such as **54 Accounts**; click it to browse those items. The legend starts with items only, and you can switch on groups, teams, tickets, and other neighbors. * **A table**: pick a table to see its items in the familiar table view, pinned to the user with a read-only filter chip such as **Account Manager is Aashna Panchal**. Add filters, search, and show archived items as usual. **Open in \[database]** takes you to the table in its database with the same filter applied. When you view someone else's profile, the tab only shows items in teams you belong to. ### What the Help Desk Agent sees The Help Desk Agent traverses the same graph when it resolves tickets. If a user opens a ticket about "my laptop," the agent walks from the user's item to their assigned computer, then to that computer's recent incidents, hardware specs, and assigned software. Configure which item types the agent can see in [Administration](/sections/documentation/databases/administration). ### Workflows on the graph Workflows can traverse the same relationships from code. The typical pattern: a server goes down, a workflow reads the graph to find every service that depends on it, then fans out remediation or notifications to the owners of each. # Ingestion Source: https://docs.serval.com/sections/documentation/databases/ingestion Pull data from any connected app into an item type, with AI-suggested field mappings An ingestion pulls data from a connected app on a schedule and writes it into an item type. You point it at an app, pick or describe the ingestion workflow, accept or adjust the AI-suggested field mappings, and Serval handles the rest: deduplication against the key field, delta detection, and deletion reconciliation. One item type can be populated by many sources. "Computer" can pull hardware specs from your MDM and financial data from your procurement tool simultaneously, with mapping priority deciding which source owns which field. Configure Ingestion panel with the four setup steps: create ingestion workflow, review and publish, run ingestion workflow, and configure mappings ## Connect a source Before you connect a source: * Create the item type (see [Schema design](/sections/documentation/databases/schema-design)) * Connect to the source app (see [Connect an application](/sections/integrations/application)) Once the item type exists and the source app is connected at the team level, follow these steps: 1. Open the item type in **Databases**. 2. Click **Configure Ingestion**. 3. Select your source app. 4. Pick or build the ingestion workflow (**Installable ingestion**, **Natural language**, or **Custom code**). See below for details 5. Run the first sync. Serval extracts a sample of raw external records. 6. Review the AI-suggested field mappings. Accept, adjust, or add to them. 7. Save. Subsequent syncs run on the schedule you set. ## Three ways to build the ingestion workflow * **Installable ingestion:** Use when an off-the-shelf workflow for your source exists in Serval's gallery (Jamf, Iru, Okta, ServiceNow, Workday, AWS, and others). * **Natural language:** Use when no installable exists, but the source has a documented API. Describe what you want to ingest ("Ingest all cards from Ramp." "Pull all active employees from BambooHR.") and [Catalyst](/sections/documentation/catalyst/overview) generates the ingestion workflow. * **Custom code:** Use when you want full control: complex pagination, custom auth, conditional logic, or a source that needs special handling. ### Installable ingestions Browse the installable gallery filtered by your connected apps. Each entry lists the source, what it pulls, and the expected fields. Install with one click and skip to mapping review. Select App to Ingest Item from dialog listing connected applications ### Natural-language ingestions Describe what you want to ingest in plain English. Be specific about the source, the resource, and any filters: * "Pull all active users from Okta, including their group memberships." * "Ingest all open expenses from Brex in the last 90 days." * "Pull every device from Intune, only Windows machines." Catalyst asks follow-up questions if it needs them (which scopes, which fields, pagination strategy), generates a draft workflow, and lets you publish once it looks right. ### Custom-code ingestions Write the workflow yourself when the source needs handling the natural-language builder can't infer: cursor-based pagination with state, multi-step ingestion (list IDs, then fetch each), conditional filtering, or auth beyond what the integration template handles. ## Review the AI-suggested mapping After the first sync brings back a sample of raw external records, Serval analyzes them and proposes mappings between external field paths and internal fields on your item type. The review screen shows each suggestion alongside a sample value: | Internal field | External field path | Sample value | | :- | :- | :- | | Serial Number | `general.serialNumber` | `C02XL0KNJG5H` | | Hostname | `general.name` | `joes-macbook` | | OS Version | `general.osVersion` | `14.5.0` | | Owner | `general.userAndLocation.email` | `joe@acme.com` | | Cost | *no suggestion* | *no match in source* | For each row you can: * **Accept** the suggestion as-is. * **Adjust** the external field path. Pick a different field from the raw record. * **Add a mapping** for an internal field the AI didn't catch. * **Skip** an internal field that doesn't have a matching source field. Mapping changes apply to items you've already ingested right away — Serval re-reads the data it already stored for them, so you don't need to wait for a sync or run one. You can come back and refine anytime. ## Fields likely to require intervention Keep an eye on the following situations, as they may require adjusting or overriding AI suggestions. * **Ambiguous source fields**. A source field named `serial` mapped to Serial Number is usually correct. A source field named `id` mapped to Serial Number probably isn't. * **Computed fields.** If your item type has a derived field (Total Cost = Unit Cost \* Quantity), the AI can't compute it. Map only what the source provides, and build derived fields with a workflow that runs after sync. * **User references.** Serval will look for fields that look like an email address, but the email must match an existing Serval user. When ingesting user reference, be sure that the source uses the same email domain. ## Multiple sources for one item type An item type can have any number of ingestion workflows, each writing different fields from a different source. This is the canonical CMDB and ITAM setup: hardware specs from your MDM, financial data from procurement, ownership and employment data from your HRIS, all written into one Computer item type. Every item is deduplicated by its key field. Each source contributes the fields it maps. ### Picking the source of truth per field When two sources both map to the same internal field, you can order them by **priority** to decide which source is more authoritative. The lower priority source still feeds the field if the higher priority source doesn't have a value. A common pattern for a "Computer" item type: | Internal field | Source of truth | Why | | :- | :- | :- | | Serial Number | MDM | Authoritative for hardware identity | | OS Version | MDM | Updates in near real time | | Hostname | MDM | Reflects what's actually deployed | | Owner | HRIS | HRIS knows employment changes first | | Cost | Procurement | Procurement has the invoice | | Status | Workflow output | A workflow sets status on its own | ## Sync schedules and deletions ### Schedule Each ingestion runs on its own interval. Set **sync frequency** explicitly, or leave it on **Default (4 hours)**. Manual sync is always available via the **Sync now** button on the ingestion config. Ingestion configuration for a Google Workspace source with the sync frequency dropdown open and mapped item fields ### Deletions The **Delete missing items** toggle controls whether Serval propagates deletions from the source: * **On:** When a record disappears from the source, the corresponding item in Serval is deleted. * **Off (default):** Disappeared records are left in place. Use this when you want to retain history of devices that left the fleet, or when the source has known cases of records flickering in and out. Serval checks for missing records after a workflow returns a complete inventory and all pages finish successfully, including on repeat syncs. Each page must identify itself as part of the full inventory. If Serval cannot confirm this for the whole sync, it skips missing-record cleanup. Incremental (delta) results must explicitly identify deleted records. An item remains if another ingestion source still supplies it. Ingestion actions menu showing run, view workflow, sync history, disable, the Delete missing items toggle, and delete ingestion ## Troubleshooting ### Reading sync status Each ingestion shows its last sync time, current phase, and whether the most recent run succeeded. The sync history lists every sync with start and end time, records added, updated, or deleted, and any failure details. A run that stored records but published none reads `Ingested, not published`: the source has no field mappings yet. For what each status and failure cause means, and for the records a sync couldn't publish, see [Issues](/sections/documentation/databases/issues). Sync history panel listing recent syncs with status, time, and records updated, plus an expanded run timeline ### Sync failed A failed sync could stem from a number of reasons: * **Workflow error:** Auth expired, source API returned 5xx, pagination broke, etc. Open the failed run and investigate with Catalyst. * **Field mapping error:** An external field path no longer exists in the source, or a value doesn't match the internal field's type (e.g. string where number expected). Fix the mapping, then re-sync. * **Schema drift:** The item type schema changed in a way that breaks the workflow. Update the schema to match what the workflow submits, or update the workflow to match the current schema. See [Schema changes](/sections/documentation/databases/schema-design#schema-changes). ### Sync runs forever Long-running syncs usually mean pagination is broken. The best troubleshooting step is to investigate the failed workflow run with Catalyst. ### Items disappearing If items are getting deleted unexpectedly: 1. Verify the **Delete missing items** toggle matches your intent. 2. Ask Catalyst to investigate the ingestion workflow and why items are disappearing 3. Cross-check the source. Is the record actually gone, or is the source paginating differently than the workflow expects? ### Mapping suggestions look wrong Re-run the first sync after the source has more representative data. The AI builds suggestions from a sample; with a few records of low diversity, suggestions may not be accurate. ## What's next Get the item type and key field right before connecting sources. Filter, sort, and traverse the context graph. Read items from workflow code. Surface them to the Help Desk Agent. Provenance shows which source wrote which value, and when. Every record a sync couldn't publish, grouped by cause. ## Workflows that run after ingested changes A workflow rule that runs after saving also runs from ingested and CSV-imported changes: one run per changed item, and none for items the sync left unchanged. Publication never waits for these workflows and never fails because of them; a failed run does not undo the published item. Runs beyond the hourly limits are held. Held and failed runs appear on the item type's **Issues** tab, where you can replay them. # Issues Source: https://docs.serval.com/sections/documentation/databases/issues See what failed to reach a database, which records it affected, and what to change An issue is one root cause on one item type. When the same problem stops twenty records from publishing, you get one issue that says it affects twenty records, not twenty near-identical rows to read through. Open an item type in **Databases** and go to the **Issues** tab. The tab itself carries a count of the records still affected, so you can see there's something to fix without opening it. ## What the list shows Each row is one issue: * **Status**: `Open` while anything is still failing, `Resolved` once everything it held up has gone through. * **Issue**: the category, a short title, and a sentence naming the field and value behind it. * **Affected**: how many records are still affected. Ingestion and workflow issues count runs, schema issues count changes, and a resolved issue reads `None open`. * **First seen** and **Last seen**: when Serval first hit this cause, and the most recent time it hit it again. Above the list, a summary counts the whole page: `12 affected records across 3 issues`. A trailing `+` means more issues are still to load. ### Categories | Category | What it means | | :- | :- | | Validation | A validation rule rejected the records. | | Publishing | A record couldn't be published for a reason other than a rule: a missing key, an unresolved relationship, or a value another record already holds. | | Ingestion | A sync run, or one of its pages, failed. | | Schema | A schema change failed, or left records to fix. | | Workflow | A workflow that runs after a saved change was held, failed, or expired. | ### Filters * **Category**: narrow to one of the categories above. * **Source**: only issues from one ingestion source. * **Rule**: only issues from one validation rule. * **Time range**: how far back to look, by the last time each issue was seen. * **Include resolved**: add issues that nothing is failing on any more. ## What an issue tells you Select a row to open it. The drawer names the item type, when the issue was first and last seen, and how many records are open out of everything it has ever affected. **Message** says what went wrong in plain terms, with the field, the value from the source row, and the record involved resolved to their names. Alongside it are the one or two places worth going next: the ingestion sources for a relationship that matched nothing, the source rows for an empty key, the record that already holds a value, or the rules that rejected a record. **Diagnostics** is collapsed and holds the raw error text, for issues that have one. **Affected records** lists every record, run, or change under the issue, 50 at a time. Each entry links to the record where there is one, lists the source rows that fed it, names the rules it broke, and gives the times it was seen and resolved. **Load more** pages through the rest. An issue involving fields or records you can't see reads **Details restricted**: the category, the counts, and the times stay visible, but the message and the evidence are withheld. Individual entries under **Affected records** are withheld the same way. ## Fixing an issue Nothing here is marked done by hand. An issue resolves when the thing that failed succeeds: the next sync publishes the record, the schema change is retried and applies, the held run is replayed. Fix the cause and the issue clears on its own. Common causes and what to change: * **Relationship target not found**: the source value doesn't match any record in the linked table. Check that the linked table is ingested and that the field is mapped. * **Key field is empty**: the source row has no value for the key field. Fix it at the source, or map the key to a field the source always fills. * **A value already belongs to another record**: two records want the same unique value. Give one of them a value of its own. * **Records rejected by validation rules**: either the data is wrong or the rule is. The issue names the rule so you can decide which. * **Run failed**: the sync itself stopped. See [Reading sync history](#reading-sync-history) below. ## Reading sync history Open the ingestion's **Sync History** to see each run's status and result. | Status | What it means | | :- | :- | | Running | The sync is in progress. The result shows the page it's on and how many records it has handled. | | Success | The run finished and published what it ingested. | | Ingested, not published | The run stored records but published none, because the source has no field mappings yet. Accept or add mappings and the next sync publishes the backlog. | | Published with failures | The run finished, but publishing rejected some of the records it ingested. | | Publishing unconfirmed | The run finished without publishing ever reporting an outcome, so what reached the database is unknown. The next sync republishes anything still missing. | | Cancelled | Someone stopped the run before it finished. | | Failed | The run stopped. The result names the cause. | A run that published only some of what it ingested says how many records publishing rejected, with a **View issues** link to the item type's issues for anyone who can open them. ### Failure causes A failed run reports a specific cause rather than a generic error: * **The extraction workflow failed on page N**: the ingestion workflow returned a failure. Open the run to see why. * **The extraction workflow didn't finish page N in time**: the workflow ran past its time limit. Usually pagination pulling too much per page. * **The extraction workflow returned a result Serval couldn't read**: the response didn't match what an ingestion workflow returns, or the run switched between a full and an incremental result mid-sync. * **The extraction workflow isn't published**: publish it, then sync again. * **Couldn't store the ingested data**: Serval couldn't write a page of records. Retry the sync. * **Ingested data couldn't be published**: the records were stored but publishing them failed. The reason is on the **Issues** tab. * **The sync stopped making progress**: the run made no headway across several attempts and stopped retrying on its own. Use **Resume** on the run to try again from where it left off. * **A newer sync run replaced this one**: a later sync started before this one finished. Nothing to do. ### Run timeline Expand a run to see its timeline: when it started, resumed, changed phase, or continued, and every failure along the way. Each event names the page it's about and carries its own diagnostics. Three events explain a run that looks clean but did less than you expected: * **Rows skipped**: a page couldn't stage some of its rows, and the event counts each kind: rows with no id, duplicate ids within one page, and deletes naming rows Serval isn't currently ingesting. * **Publishing skipped**: the run ingested records but published none, because the source has no field mappings. * **Sync ended after stalling**: the run stopped making progress and Serval ended it. ## What's next Most publishing issues trace back to a field mapping. A rule that rejects good data is a rule worth changing. # Manual data entry and bulk import Source: https://docs.serval.com/sections/documentation/databases/manual-data-entry Add and edit items through the UI, or bulk import from CSV Manual entry is the right tool for items that aren't ingested: spreadsheet-sourced data with no API behind it, a quick correction to a single value, or a one-time load while you wait to wire up the ingestion. For anything ongoing, use [Ingestion](/sections/documentation/databases/ingestion). ## When to use manual entry Use manual entry for unique, non-recurring cases that can't be synced with an API. * **Importing from a spreadsheet:** For bulk data from a spreadsheet with no API behind it, use CSV import. * **One-off item:** For a one-off item that isn't tracked anywhere else, add through the UI. * **Editing:** To fix a wrong value on a single item, edit through the UI. Don't use manual entry for recurring data from any system with an API or data you need refreshed automatically. Instead, use [Ingestion](/sections/documentation/databases/ingestion). Any value you set manually is overwritten on the next sync unless you pin the field to keep a manual value. See [Multiple sources for one item type](/sections/documentation/databases/ingestion#multiple-sources-for-one-item-type) ## Add an item 1. Open the item type in the Databases tab. 2. Click **Add Item->Create item manually**. 3. In the **Create Item** popup, fill out the fields. Create Item dialog with serial number and name required, plus optional fields like RAM, disk size, and OS version The key and name fields are required. All other fields are optional unless you're creating an edge-type relationship (which requires both endpoint fields). If you enter a key that already exists, creation fails. If you need to update by key, use edit on the existing item or update by CSV import. ## Edit field values For an item reference field, select the item type if needed, then search for the item or scroll to load more options. Item detail view for a MacbookPro15 item showing its key and name fields and source 1. Click any item to open its detail view. 2. Click any field to edit inline, or click the edit (pencil) icon to edit all fields. 3. Changes write through immediately. Every edit is recorded in the item's history with author, timestamp, and the previous value. For more on item history, see [Administration](/sections/documentation/databases/administration). Item edit view for MacbookPro15 with editable name field and Save and Cancel actions ### Edits and ingestion If a field is fed by an ingestion config, a manual edit gets overwritten on the next sync that maps to that field. To make a manual edit persist: * Pin the field when prompted, which keeps your manual value until you unpin it, or * Remove the mapping for that field on the ingestion config, or * Lower the ingestion mapping's priority so manual entry wins, or * Update the value at the source instead of in Serval. Fields that no ingestion maps to are safe to edit. Provenance in the item's history shows whether each value came from manual entry or from a specific ingestion run. ## Bulk import from CSV Use CSV import for one-shot loads from a spreadsheet, vendor export, or migration from another system. ### CSV format * The first row is a header row. * Map a column to the item type's key field. This is required for a successful import. * All other mapped columns are optional. * Columns you don't map are ignored. * Column order doesn't matter. | Type | How to format the value | | :- | :- | | Text | Raw string | | Number | `1234` or `1234.56`. No commas for thousand separators | | Boolean | `true` or `false`. Also accepted: `1`/`0`, `yes`/`no`, `on`/`off`. | | Timestamp | ISO 8601 is recommended (e.g. `2026-06-25T14:00:00Z`). Date-only values such as `2026-06-25` are also accepted. | | Enum | The option **value** (canonical key), not the display label. Matching is case-insensitive. | | Multi-select | One option value per cell. Pipe-separated values (e.g. `Engineering\|Security\|Finance`) aren't supported in CSV import. | | Entity reference | The referenced entity's (item's) key value. UUID and external ID are also accepted. | | User reference | The user's email address. UUID is also accepted. | | File | Not supported in CSV import. Upload files through the UI. | ### Importing 1. Open the item type in **Databases**. 2. Click **Add Item->Import from CSV.** 3. Upload the file. Serval validates the header row against the item type's fields. 4. Review the preview. Serval shows how many rows will be inserted, how many will update existing items (matched by key), and any parse errors per row. 5. Confirm. Import assets from CSV dialog with a Choose CSV file button and Upload and analyze action Rows with parse errors are skipped, not retried. Fix them in the source CSV and re-import. Matching by key means re-importing a corrected row updates the right item, not a duplicate ### Key collisions and updates Import deduplicates by the key field. A row whose key matches an existing item updates that item's fields with the values in the CSV. Fields not present in the CSV are left unchanged. ## What's next Replace manual loads with an ingestion that keeps the data fresh. Verify the import landed correctly and start querying. Provenance shows whether each value came from manual entry, CSV, or a specific ingestion run. ## Workflows that run after a change A workflow rule on the item type can run a workflow after an item is created, edited, archived, restored, or deleted, whether the change comes from the database interface or the API. Rules are configured on the item type's **Rules** tab; see [Workflow rules](/documentation/databases/schema-design#workflow-rules). The item is saved first. The workflow then receives the item's values before and after the change and who made it. A failed run never undoes the edit, and repeating an edit without changing its values does not start another run. Runs are limited per rule and per team each hour; changes beyond the limit still save, and their runs are held. Held, failed, and expired runs appear on the item type's **Issues** tab, where you can open the run or replay it. # Databases overview Source: https://docs.serval.com/sections/documentation/databases/overview Ingest assets and configuration items from any source, and reference them in tickets, workflows, and more. Serval uses databases to read and write data from workflows, skills, tickets, campaigns, and journeys. Each database can hold one or more tables, each of which contains one or more items. An item is a single table row with typed fields like text, dates, numbers, or references to other items. **"Items" and "Entities" are interchangeable terms.** Both terms are used in relation to Serval databases. Item is the term used in the UI that refers to a single row in a database table. Entity is the technical term used in the workflow code, API, and field types. ## Database features * **AI-native ingestion.** Describe a new ingestion in plain English ("ingest all computers from Iru") and Serval generates the requisite workflow. Serval also suggests how external fields map to your schema, so you review and accept instead of wiring mappings by hand. * **Multi-source per type.** One item type can pull from many sources. Sync a computer's specs from your MDM and its financial data from your procurement tool. Pick the source of truth per field. * **Context graph.** Relationships between items are first class, traversable, and visible. See every device downstream of a server, every license assigned to a user, the full dependency chain of a CI. * **Connected to the rest of Serval.** Workflows read and write items. Skills surface item data to the Help Desk Agent. Campaign responses can be written to databases. See every ticket associated with an item. * **Full provenance.** Every change to every field is recorded with author, source, and timestamp. Trace what changed and when, even as assets move between owners. * **Custom fields on people.** The built-in Users database takes your own fields, populated from your IdP, and surfaces them on every user profile. See [User custom fields](/sections/documentation/databases/user-custom-fields). ## When to use databases * **Single source of truth for hardware, software, and licenses.** Pull from your MDM, procurement tool, and IdP into one schema. Pick the source of truth per field. Track provenance through every transfer. * **CMDB for change management and impact analysis.** Model CIs and their relationships as item types. The context graph traces downstream dependencies. Workflows can fire when an upstream CI changes. * **Reference data for tickets, catalog items, or workflow state.** Any item type can back custom ticket fields, catalog reference options, journey metadata, and persistent workflow state. ## What you can do with Databases Define item types, fields, and relationships. Evolve the schema as your needs change. Pull data from connected apps with AI-suggested field mappings, multi-source reconciliation, and scheduled syncs. Filter, sort, save views, and traverse the context graph. Reference items from workflow code, surface them to the Help Desk Agent, and report on them in dashboards. *** ## Next steps Define an item type, add fields, populate, and query end to end. Start syncing from your MDM, IdP, or procurement tool. # Build your first item type Source: https://docs.serval.com/sections/documentation/databases/quickstart Define a schema, populate it, and query the result This guide walks you through creating an item type, populating it with a few items, browsing the result, and connecting an ongoing data source. By the end, you'll have a working table you can query from anywhere in Serval. ## Create your first item Create item type dialog showing icon and name, item key, parent item type, and the key and name fields 1. **Navigate to your team in the left panel and select Databases** 2. **Create the item type** Click "New item type" in the top right. Name it after the thing you want to track. For this example, use "Computers." For this example, skip the optional field **Parent Item Type**. 3. **Add anchor fields** Every item type needs two anchor fields: * A unique **key field**, used for deduplication when syncing from external sources. For this example, use "Serial Number." * A descriptive **name field**, used as the display label. For this example, use "Hostname." 4. **Add other fields** Add typed fields for everything else you want to track. For this example, add these: * "OS Version" (text) * "Cost" (number) * "Owner" (user reference) * "Status" (enum: Active, In Repair, Retired) 5. **Add a few items by hand** Click **New item** and fill in the fields for two or three computers. Hand entry is fine for a quick test. Once you're ready to sync from a real source, you will set up ingestion. 6. **Browse and filter** Open the item type's list view. Filter on any field. Sort on any field. Save the view if you'll come back to it. Filters and saved views are private unless you share the view explicitly. Try filtering by "Status = Active" and sorting by "Cost" descending to see the most expensive active machines. 7. **Connect a source** Once the schema is settled, replace manually-created items with a live ingestion. Click **Connect a source** on the item type. Pick an app you've already connected to Serval (your MDM, IdP, or procurement tool), choose an installable extraction workflow or write one in natural language, and accept the AI-suggested field mappings. Serval handles the first sync and keeps the item type fresh on the schedule you set. For more information on ingestion (including full setup, multi-source reconciliation, and troubleshooting), see [Ingestion](/sections/documentation/databases/ingestion). ## Tips for building an item type ### Pick a stable key Choose a key field that's unique and unchanging. Serial numbers, asset tags, and email addresses make better keys than display names. ### Type narrowly Use enums for fixed sets and user references for ownership. Use text fields as a fallback, not a default. ### Settle the schema before ingesting Changing field types after ingestion is supported but triggers a schema migration. Take time to think through your schema before you begin ingestion. ## What's next Model relationships, evolve fields safely, and use reference-data schemas for lookup tables. Feed one item type from multiple apps and pick the source of truth per field. Read and write items from workflow code. Surface item data to the Help Desk Agent. # Schema design Source: https://docs.serval.com/sections/documentation/databases/schema-design Define item types, fields, relationships, and how to evolve them over time Every database in Serval is a typed schema: a set of item types, each with named fields. Workflows, skills, ticket fields, and Help Desk Agents all read from this schema. It needs to stay stable enough to query reliably, and flexible enough to evolve as your business changes. This page covers how to model item types, choose field types, model relationships, and change the schema after data is in place. ## Item types An item type is the schema for one kind of thing you track, such as computers, software licenses, services, or cost centers. Each instance of the type is a single item. In other database architectures, an item type would correspond to a table, and each item would correspond to a row. ### Creating an item type Create item type dialog showing icon and name, item key, parent item type, and the key and name fields 1. In a database, use the **New table** button to create a new item type. (Its chevron menu also offers **New relationship** — see [Relationship (edge) types](#relationship-edge-types).) 2. Enter a name for the item type. 3. Optionally choose a **parent item type.** Use a parent when several related types share a base set of fields. For instance, setting "Asset" as the parent of "Computer", "Phone", and "Monitor" means you can query "all assets" without joining three tables, while each child still carries its own type-specific fields. 4. Add additional fields as needed ### Parent-child hierarchy Child types inherit every field from their parent type. For instance, add a field to "Asset" and it appears on "Computer", "Phone" and "Monitor" automatically. Child types can add their own fields as well. Multiple levels of nesting are supported, but deep hierarchies can make schema changes difficult to understand. One or two levels of inheritance should handle most real-world models. ## Fields Fields are typed columns on an item type. The available field types: | Field type | What it stores | | :- | :- | | Text | Single-line string | | Number | Integer or decimal | | Boolean | True or false | | Timestamp | ISO 8601 timestamp | | Enum | One value from a fixed list of options | | Multi-select | Zero or more values from a fixed list | | Item reference | Pointer to another item, typed by entity type | | User reference | Pointer to a Serval user | | Unique | String guaranteed unique across the entity type | | File | Attached file, one per record | ### File fields in workflow emails A file field's value is the file's id. A workflow that reads the record can embed an image stored in that field inline in an email sent with `serval.common.sendEmailToUser`, so a header or footer banner travels inside the message instead of loading from a link: ```typescript theme={null} await serval.common.sendEmailToUser({ recipientEmail: person.email, subject: "Your laptop is ready", body: `IT Service Desk

Pick it up at the front desk.

`, inlineImages: [{ contentId: "banner", entityFileId: brand.header_banner }], }); ``` Each `inlineImages` entry pairs a `contentId`, the token the HTML body references as `cid:`, with the file id from a record in the sending team's database. The file must be a PNG, JPEG, or GIF of 2 MB or less, and the workflow's team must be able to read the record that holds it. Files on sensitive fields can't be embedded. ### The key field Every item type designates one field as the key field. The key is what Serval uses to deduplicate when syncing from external sources. If a sync sees the same key twice, it updates the existing item instead of creating a duplicate. Primary-key lookups with `serval.common.getEntity` or the search API's `key` parameter use the same normalization as key uniqueness: `CAM-000004`, `cam-000004`, and `CAM 000004` identify the same item. The stored field value keeps its original casing. Filtering directly on a field still uses the selected filter operator's comparison rules. Pick a stable and unique identifier from the source system. For example: * **Computer:** serial number, MDM device ID, or asset tag * **User:** email address or IdP user ID * **Software License:** license key * **Service:** service code or CMDB `sys_id` Display labels (hostname, employee name, product name) aren't stable keys. People rename things; serial numbers don't change. ### The name field The name field is the display label shown in the list view, ticket attachments, workflow output, and the context graph. Pick whatever a human would call the item: hostname for computers, full name for users, "Adobe Creative Cloud, Marketing seat" for licenses. ### Item reference field Two item types can be linked with an item reference field. A computer can carry an "owner" field pointing at a user. A service can have a "depends\_on" field pointing at other services. An incident can have an "affected\_asset" field pointing at a computer. An item reference declares which item types it accepts: a single type, several types (an "affected item" field might allow both computers and software licenses), or **Any item type** to leave it open. When more than one type is allowed, picking a value starts with choosing one of the allowed types. Item references are first-class: queries traverse them, and the [context graph](/sections/documentation/databases/browsing-and-querying#the-context-graph) visualizes the result. ## Validation rules Rules are available only when validation rule management is enabled for your team. You also need permission to manage rules. Workflow rules additionally require workflow rules to be enabled for your team and permission to manage workflow rules. Validation rules reject item changes that do not meet your requirements. A rule can combine required values, text patterns, number limits, field comparisons, and conditions about field changes. Teams with workflow rules can also create rules that run a workflow after an item changes; see [Workflow rules](#workflow-rules). 1. Open the item type's **Rules** tab. 2. Select **Create rule**. 3. Enter a **Rule name**. 4. Under **Check on**, select **Creating**, **Updating**, or **Unarchiving**. 5. To limit when the rule applies, select **Only apply when** and add conditions. 6. If your team has workflow rules, keep **Require values** selected under **Then**. 7. Under **Require**, add the conditions that the item must meet. 8. Enter the **Error message** that people see when the rule rejects a change. 9. Select **Create rule** to save it. Both condition sections support **Add condition** and **Add group**. Conditions in a group are joined with **AND** or **OR**. Select the connector between two conditions to change it for the whole group. Groups can contain one additional level of groups. **Only apply when** controls whether the rule runs. If these conditions are false, Serval skips the rule. Otherwise, the conditions under **Require** must pass. For example, a rule can apply only when Status is Active. Its requirements can combine Email **is not empty**, Email **matches regex**, and Seats **is between** 1 and 100. An empty field fails every value condition except **is empty**. **is between**, **is at least**, and **is at most** include their boundary values. Regular expressions use Go (RE2) syntax. The anchors `^` and `$` restrict a pattern to the entire value. Each condition picks a field and then a condition from three sections. **Value** checks the field's value. **Another field** compares the field with another field of the same type. **Change** supports changed, did not change, changed from one value to another, and increased or decreased for numbers and dates. **Change** conditions are available only when **Updating** is the only selected operation. Rules do not scan existing items when you save them. On subsequent selected operations, applicable rules evaluate all their requirements, including fields that did not change. Schema requirements, such as the key field, still apply independently. ### Workflow rules When workflow rules are enabled for your team, the **Rules** tab lists validation rules and workflow rules together. The **Then** column shows what each rule does: **Require** for validation rules and **Run** a workflow for workflow rules. To create a workflow rule, follow the steps above and, under **Then**, choose **Run a workflow after saving**. Workflow rules can also check on **Archiving** and **Deleting**. * **Workflow** lists the team's deployed workflows. **Build the workflow in Catalyst**, next to it, opens Catalyst with a prompt that already names the table, the rule, and what the workflow receives; describe what should happen and it drafts the workflow. Publish the workflow, then choose it here. * **Version** defaults to **Deployed version**, which runs whichever version is deployed when a change is saved. Pin a version to keep running it after a new deployment. The item is saved first; the workflow runs with the values from that change and never blocks or undoes it. Held and failed runs appear under **Issues** below the rules, where you can open the run or replay it. The rule type can't change after the rule is created. ### Normalization rules A normalization rule maps the values people and syncs type into a text field onto a link or choice field on the same item type. For example, a rule can read a Manufacturer (raw) text field and set a Manufacturer item reference, so that `Microsoft Corp.`, `microsoft corp`, and `Corp, Microsoft` all link to the same Microsoft item. 1. Open the item type's **Rules** tab. 2. Select **Create rule**, then **Normalization**. 3. Under **Raw value**, select the text field to read. 4. Under **Maps to**, select the item reference or choice field to set. 5. Optionally, under **Save version to**, select a text field to receive version numbers. 6. Keep **Run on existing records** selected to normalize items that already have a raw value. 7. Select **Create rule**. The rule runs whenever an item is created, updated, or synced, before validation rules. It matches a value when it is the same as the name of an item or option in the output field, or as an alias, ignoring case, punctuation, accents, and word order. When **Save version to** is set, a version number such as `2.4.1` or `v10.2` is moved from the raw value to that field first, so every version maps to the same item. A plain number such as `2013` stays part of the name. A value with no match leaves the output field empty, and appears on the rule's **Pending values** tab and as an **Unmatched value** issue. Map a pending value to an existing item or option, create a new one, or ignore it. Where Serval finds a likely match, it suggests it. Mapping a value adds an alias and updates every item that has that value. The **Aliases** tab lists the aliases, and you can import aliases from a CSV file with `raw` and `canonical_name` columns. A rule doesn't overwrite an output value that someone set directly. Disabling a rule stops it from mapping new values. Deleting a rule keeps the values it already set. The output field can't change after the rule is created; to map to a different field, delete the rule and create another one. ## Relationship (edge) types When a relationship is many-to-many and carries information of its own (such as a software license assigned to a user with a start date, a seat ID, and an approver), an item reference field on one side isn't enough. Create a **relationship (edge) type**: a type that exists to connect two others. An edge type has exactly two single-valued item reference fields, one for each endpoint. You name both directions when you create the relationship type. The field names become the direction labels in the context graph. ### Creating a relationship type Relationship types have their own creation flow, separate from item types: Open the **New table** button's chevron menu and choose **New relationship**. Enter a name for the relationship type, such as **Software access**. Choose the **Source item type** and **Target item type**, such as **Employees** and **Software**. Leave either unset to allow any type on that end. Enter the two **Label** values. These name the relationship's reference columns; they aren't columns you select from either existing table. A live preview shows how the relationship reads in each direction. Use **Add Field** to store information about the connection, such as grant date or access expiration date. Click **Create relationship type**. Populate the relationship using an ingestion workflow, or manually link existing items by opening an item and selecting **Related → Link**. If ingestion can't find a linked item, see [Relationship target not found](/sections/documentation/databases/issues#fixing-an-issue). The source and target item types are fixed once the relationship type is created. In its settings you can rename the direction labels (the underlying field keys stay locked), but you can't change or delete the endpoint types. Use an edge type when: * The relationship is many-to-many * The relationship carries fields of its own (dates, seat IDs, justifications, costs) * You want both endpoints queryable by relationship For one-to-many relationships with no extra fields, a plain item reference on the "many" side is simpler. ## Reference data schemas Reference data schemas hold lookup values used by other item types: department codes, cost centers, region IDs, and ServiceNow reference rows. They're queryable like any other item but don't show up in asset-style browse experiences. Use a reference data schema when: * The data is a lookup, not a primary asset * You expect to reference it from other item types via an item reference field * You don't want it cluttering the main asset list ## Schema changes Serval supports adding, renaming, retyping, and deleting fields after data is in place. Most changes run as asynchronous schema migrations; you can poll the migration to track completion. ### Adding a field Adding a field is the safe operation. Existing items start with the field unset. New and updated items populate it. No data conversion runs. ### Renaming a field Renaming a field updates the display name and regenerates the field key from the new name. Workflow code that references the old key needs to be updated. Existing field values are untouched. ### Changing a field's data type You can retype a field after the fact. The migration runs asynchronously and converts existing values where possible. Most type changes are attempted value-by-value and fail the migration on the first unconvertible value. Common conversions and how they behave: | From | To | Conversion | | :- | :- | :- | | Text | Number | Parsed; rows that don't parse fail the migration | | Text | Timestamp | ISO 8601 strings convert; other formats fail | | Text | Enum | Existing values must already match a defined option | | Enum | Multi-select | Each single value becomes a one-element list | | Number | Text | Always succeeds | The following conversions are always blocked: | From | To | Conversion | | :- | :- | :- | | File | (Can't convert) | Always fails | | Item references to edge endpoints | (Can't convert) | Always fails | | Key fields | (Can't convert) | Always fails | | Item reference | Unique | Refused; add a new Unique field instead | A conversion to **Unique** fails validation when two or more items already share a value on that field. Values are compared the same way as key lookups, so `CAM-000004`, `cam-000004`, and `CAM 000004` count as the same value. The error reports how many values are shared. Make those values distinct, then retry. If conversion fails for any row, the migration fails and the field stays at the old type. Fix the offending rows first, then retry. Converting to **Unique** is the exception: two items can hold the same text, but only one can hold it once the field is unique. The migration completes, the first item to be converted keeps the value, and every later item that wanted the same value is left with the field empty. Each one is listed on the item type's **Issues** tab as "Value already used by another record", with a link to the item. Give those items a value of their own and the issue clears. Values match the same way keys do, so `CAM-000004`, `cam-000004`, and `CAM 000004` count as the same value. Saved views that filter on the field drop that filter, because its value was typed to the old type. If an audit plan's scope filters on the field, the retype is refused until you edit the plan. A retype is one change per request. To rename **and** retype a field, run two migrations back to back. ### Deleting a field Deleting a field removes it from the item type and, by default, from every descendant type that inherits it. Saved views drop any filter, sort, or column on the field. If an audit plan's scope filters on the field, the deletion is refused until you edit the plan. Deletion is destructive. Field values for the deleted field aren't recoverable through the API. ## Deleting an item type Deleting an item type also deletes all of its child types. The items themselves aren't permanently removed. Instead, they stay hidden from queries, but are kept for audit. Confirm the impact before deleting. There's no API recovery once you delete. Any workflow, skill, or ticket field that references the type will fail to resolve. ## What's next Connect an external source and let AI-suggested mappings handle the wiring. Add or import items through the UI and bulk CSV. Read and write items from workflow code. Surface them to the Help Desk Agent. Control who can view and edit items, and trace every field change. # User custom fields Source: https://docs.serval.com/sections/documentation/databases/user-custom-fields Define org-wide custom attributes on people, populated from your IdP and surfaced on every user profile Every organization gets a built-in **Users** database, holding one row per person in Serval. Turning on user custom fields lets you add your own typed fields to it: cost center, employee type, badge ID, start date, or anything else your IdP knows about people that Serval doesn't model natively. Once defined, those fields appear as **Custom attributes** on each person's profile, and become available as criteria in access profiles, routing rules, SLA attachment, queue filters, and ticket list filters. **"User custom fields" and "custom attributes" are the same thing.** User custom fields is the capability you turn on and the schema you define. Custom attributes is the section those fields render in on a person's profile. ## Turn on the capability The toggle is in a team's **Settings → Capabilities**. 1. Enable **Databases** first. Custom fields are defined on the Users database, so the User custom fields toggle stays locked until Databases is on. 2. Enable **User custom fields**. On enable, Serval creates the organization's Users schema and immediately kicks a sync sweep, so values populate right away instead of waiting for the next scheduled user sync. **The setting is org-wide, even though it lives in a team's settings.** The team that turns it on becomes the owner and ingests users for the whole organization. Every other team's toggle locks with a note naming the owner. To hand ownership to a different team, turn it off on the owning team first. **Choose IT as the owner in most cases.** The owning team is the one whose connected apps populate these fields, and IT typically administers the identity and directory apps that carry the attributes you want: Okta, Google Workspace, Slack, and similar. Putting ownership anywhere else means the team that manages those app connections isn't the team that owns the schema they feed. The dependency also runs backwards. While user custom fields are on, that team's Databases toggle stays locked, so turn custom fields off before disabling Databases. ## Define the fields The Users table appears in the owning team's Databases alongside your other tables. Add fields to it exactly as you would any other item type, and every field type is available. See [Schema design](/sections/documentation/databases/schema-design#fields) for the field types and for how renames, retypes, and deletions behave. The Users table's key field holds Serval's internal user ID rather than a user-facing attribute, so it's excluded everywhere fields are listed or picked. The Users table behaves differently from a table you create: * There's no **Add item** button. Rows are created by user ingestion, or on the first manual save against a person who doesn't have one yet. * It can't be deleted. * User search backs the browse experience rather than the standard item list, so the archived-items toggle doesn't apply. ## Populate the fields ### From a connected app Values come from your connected IdP's user payloads. Map them on the Users table's **Sources** tab, using the same multi-source mapping UI as any other database. Several sources can contribute to the same table, and you pick the source of truth per field. See [Ingestion](/sections/documentation/databases/ingestion). ### By hand on a profile Open a person's profile, go to the **Attributes** tab, and click any value under **Custom attributes** to edit it in place. Values you can edit show a pencil next to them. ### Pinning A manual edit pins the value by default, which stops ingestion from overwriting it. Unpin it to let connected apps update the field again, or pin an unpinned value to freeze what's currently there. Every write is recorded. Expand a row to see its history: previous values, whether each was pinned, the user or connected app that set it, and when. ## Where user custom fields can be used | Surface | Available fields | | :- | :- | | Access profile membership criteria | Text, Unique, Enum, Multi-select | | Routing rule requester conditions | Text, Unique, Enum, Multi-select | | SLA attachment criteria | Text, Unique, Enum, Multi-select | | Queue filters | All field types | | Ticket list filters | All field types | The split isn't arbitrary. Access profiles, routing rules, and SLA criteria match on value labels, so they only offer the types that can produce a populated value picker. Offering the others would let you build a rule that matches nobody. Queue and ticket filters use typed predicates instead, so they can express Number, Boolean, Timestamp, and User reference comparisons too. Surfaces that author criteria against these fields hide the option entirely until the org has opted in and defined at least one usable field. ## Permissions | Action | Required permission | | :- | :- | | Turn the capability on or off | Update settings, on that team | | View custom attributes | View items, on a team that can see the schema | | Edit custom attributes | Update items, on the **schema-owning** team | **Editing custom attributes isn't gated the same way as the default attributes on the same tab.** Default attributes (name, timezone, language, manager) are editable by the person themselves or any org admin. Custom attributes are entity writes, authorized against the team that owns the Users schema. An org admin who lacks item-edit permission on the owning team sees custom attributes as read-only while the default fields stay editable. Both sections are read-only on a deactivated user's profile. System users show no default attributes at all, and their custom attributes are read-only. ## What's next Field types, key fields, and how to change a schema after data is in place. Connect an IdP and map its user payload onto your fields. Build profile membership criteria from user attributes. Control who can view and edit items, and trace every field change. # Access for Users Source: https://docs.serval.com/sections/documentation/end-user/end-user-access How to request, extend, and manage access to applications ## Requesting Access Request access through Slack, Teams, or app.serval.com. Serval guides you to the right access level, even if you don't know the specific role you need. For example, you may know you need Figma access but not whether that's Editor, Admin, or Group Admin. **Request access two ways:** 1. **Natural language requests** through a conversational portal (Slack, Teams, or any help desk portal). You can make imperfect requests and Serval guides you to the correct type of access. Slack conversation showing user requesting Figma access with Serval guiding them through role selection 2. **Catalog in app.serval.com**: Click **New Request** → **Browse Catalog** → select **Access** → choose the application and role → fill in required details → click **Request access** Serval application interface showing the access request form with app selection and role options ### Scheduling a Start Time When you request access, you can choose a start time instead of right away. Set a start time on the request, and after it's approved, Serval provisions the access at that time rather than immediately. You can schedule up to 90 days out, and the start time can't be in the past. This is useful when you know you'll need access on a specific future date, so the access is ready without anyone remembering to provision it manually. Common use cases include a project kickoff or a new hire's start date. *** ## Managing Active Access Once your access request is approved and provisioned, you can manage it throughout its lifecycle. View your current access duration, time remaining, and expiration time directly in the access request card. ### Extending Access Need more time? Request an extension before your access expires: * **Via Slack/Teams**: Ask Serval to extend your access. For example: "Can I extend my AWS access for another hour?" * **Via app.serval.com**: Open the ticket where you requested access and use the edit option to request more time. You can request an extension even while your access is still being provisioned. The new duration takes effect once both provisioning completes and the extension is approved. ### Shortening Access If you finish early and no longer need access, you can request to shorten it: * Ask Serval to reduce your access time, or edit the duration in the access request card. * Shortening access helps maintain least-privilege principles. Both extensions and shortenings may require approval depending on your organization's access policies. *** ## Amending Requests Before Approval Changed your mind about how long you need access? You can amend your request before it's approved: 1. Open the original ticket where you requested access. 2. Request a different duration (longer or shorter). 3. Your new request replaces the pending one. The approver sees only your final requested duration. If you amend multiple times before approval, only the last amendment matters. *** ## Canceling Requests You can cancel access requests at different stages: If you no longer need the access you requested, cancel it before approval: * Ask Serval to cancel the request, or use the Cancel button in the access request card. * The entire access request is concluded and no access is granted. If you requested an extension but changed your mind: * Cancel the pending extension using the Cancel button. * Your original access remains active with its current duration. * Only the extension request is canceled, not your existing access. *** ## Reviewing Personal Access View your personal access history from app.serval.com: Access sidebar → select "My Access" → View historical log of all access requests and relevant tickets. Admins can create a workflow that lets you request a CSV download of all your historical access requests. *** ## Common Questions When your access duration ends, Serval automatically revokes the access using the same method it was granted (removing you from a group, calling an API, etc.). You'll need to request new access if you need it again. If your access recently expired but hasn't been fully deprovisioned yet, you may be able to extend it without starting a new request. Otherwise, you'll need to submit a new access request. Approvers can modify the duration when approving your request. For example, you might request 2 hours but be approved for 30 minutes based on policy or business needs. The access request card shows your current duration, time remaining, and expiration time. You can also ask Serval about your active access. # End User Guide Source: https://docs.serval.com/sections/documentation/end-user/end-user-guide Your complete guide to getting help through Serval on day one and beyond Welcome to Serval! This guide shows you how to get help from your company's support teams using Serval—an AI-powered help desk that makes getting assistance fast and easy. The specific questions and workflows available to you depend on what your organization has configured. The examples below illustrate the types of requests you can make. *** ## How Serval Works When you ask for help, Serval's AI assistant works to resolve your request: 1. **Understands your question** — Serval reads your message and determines what you need 2. **Searches for answers** — Checks your company's knowledge base and documentation and provides you with the proper answer or link to an article 3. **Automatically takes action** — Executes automations for common requests 4. **Connects you to a human** — Escalates to the right team member when needed, with full context You'll always know what's happening—Serval keeps you informed throughout the process and tells you when a human takes over. *** ## Ways to Get Help Depending on how your organization has configured Serval, you can reach out through multiple channels. Your admin will tell you which of these channels are configured and how they are named. Message Serval directly in Slack or Microsoft Teams—either via DM, slash commands, or designated help channels Send an email to your company's support address Go to [app.serval.com](https://app.serval.com), log in, and submit a ticket directly. Confirm with your IT admin that you can directly access the portal Your admin will let you know which channels are available at your organization. ### Routing Your Request **If you know which team to contact:** Either use the designated Slack/team channel provided by your admin, or select the appropriate team from the dropdown menu (e.g., IT, HR, Operations) in app.serval.com. **If you're not sure:** Just send your message via DM to Serval, relevant email, or [app.serval.com](https://app.serval.com)—Serval will automatically route your request to the right team based on your question. ### Submitting a Private Request For sensitive requests—like salary questions, personal device issues, or HR matters—you have options to keep your conversation private: * **Direct message the Serval bot** in Slack or Teams for a one-on-one conversation * **Submit via the web portal** at [app.serval.com](https://app.serval.com) where only you and the support team can see it * **Email** your support address directly Private requests are only visible to you and the support team handling your ticket. Other employees in your workspace cannot see your conversation. Learn about slash commands, message actions, @mentions, and other Slack-specific features *** ## What You Can Ask The questions you can ask depend on which channel or team you're reaching out to. Here are common examples organized by team. This will differ across organizations: **Software & Access** * "I need access to \[application name]" * "How do I install \[software]?" * "I forgot my password" * "Can I get access to the shared drive?" * "I need a license for Figma/Notion/etc." **Equipment & Devices** * "My laptop is running slowly, can you help?" * "I need to request a new monitor" * "How do I connect to the office printer?" * "My keyboard stopped working" **Connectivity & Troubleshooting** * "I can't connect to VPN" * "WiFi isn't working in the office" * "My email isn't syncing" * "Two-factor authentication isn't working" **Security** * "I think I clicked on a phishing link" * "How do I report a suspicious email?" * "I need to encrypt a file" **Benefits & Compensation** * "Where can I find information about health benefits?" * "How do I update my direct deposit?" * "When is open enrollment?" * "How do I access my pay stubs?" **Time Off & Leave** * "How do I request PTO?" * "What's the parental leave policy?" * "How many sick days do I have left?" * "How do I request a leave of absence?" **Policies & Documents** * "Where's the employee handbook?" * "What's the remote work policy?" * "How do I update my emergency contact?" * "Where do I find the expense policy?" **Career & Development** * "How do I sign up for training?" * "When are performance reviews?" * "How do I request a job title change?" * "Where can I find internal job postings?" **Office & Workspace** * "How do I book a conference room?" * "The AC isn't working on floor 3" * "I need a standing desk" * "Where are the office supplies?" **Access & Badges** * "I lost my office badge" * "Can I get visitor access for a guest?" * "How do I get building access after hours?" * "I need parking garage access" **Travel & Expenses** * "How do I book travel?" * "What's the process for expense reimbursement?" * "I need a corporate card" * "Where do I submit receipts?" **Equipment & Supplies** * "I need office supplies ordered" * "How do I request new furniture?" * "The coffee machine is broken" These are just examples. Your organization may have custom workflows for specific requests—just ask naturally, and Serval will guide you through the process! *** ## Tips for Getting the Best Help Include relevant details upfront. Instead of "I need access," try "I need access to the AWS production account for the analytics project." Mention what you've already tried, any error messages you're seeing, or deadlines that are relevant. This helps get you a faster resolution. If you have multiple unrelated requests, submit them separately so each gets tracked and resolved properly. Continue your conversation in the same thread. Serval remembers context from earlier messages. Serval uses emojis to show status: * ⏳ Working on your request * ✅ Successfully completed * ❌ Cancelled or unable to complete *** ## What to Expect ### Instant Answers For common questions, Serval pulls answers directly from your company's knowledge base. You'll get a response in seconds with links to relevant documentation. ### Automated Workflows For requests like access provisioning, software installation, or common IT tasks, Serval can handle the entire process automatically—including getting approvals if needed. ### Human Support When Serval can't resolve something automatically, it creates a ticket and routes it to the right team. You'll be notified when a human agent picks up your request, and you can continue the conversation naturally. Even when a human takes over, everything stays in the same conversation thread. No need to repeat yourself! *** ## Checking Your Request Status You can check on your requests in several ways: * **Ask Serval directly**: "What's the status of my access request?" * **Check your conversation thread**: Status updates appear in your original conversation * **Web portal**: If your company has enabled it, visit the Serval web portal to see all your tickets *** ## Common Questions When you DM Serval, your request is visible only to you and the support team handling it. Others cannot see your conversation. Serval always identifies itself as an AI assistant. When a human agent joins the conversation, you'll receive a notification letting you know. Yes! You can attach images, screenshots, logs, or documents directly in your conversation with Serval. Try rephrasing your request with more specific details. If Serval still can't help, it will automatically escalate to a human agent. Yes, just tag @Serval and say "cancel this request" or "never mind" in your conversation thread, and Serval will close the ticket. Yes. In the web portal, click the globe icon in the top bar and choose a language. Available languages are English, German, Spanish, French, French (Canada), Japanese, Portuguese, Portuguese (Brazil), and Russian. Your choice is saved to your account. # AI Tools (MCP) Source: https://docs.serval.com/sections/documentation/end-user/mcp-quickstart Connect Claude and other AI assistants to Serval You can connect AI assistants like Claude directly to Serval. Once connected, you can create tickets, run workflows, check request status, look up people, and more — all through natural conversation with your AI assistant. Your admin may need to enable MCP access for your organization. If you don't see a way to connect, ask your IT admin. *** ## How It Works 1. **Configure** your AI tool with Serval's server URL (one-time setup) 2. **Approve access** through your browser when the tool first connects 3. **Ask naturally** — your AI assistant calls Serval on your behalf *** ## Setup ### Find your server URL Each Serval region runs its own MCP server. Pick the server URL that matches the address you use to sign in to Serval: | Your Serval sign-in address | Server URL | | - | - | | `app.serval.com` or `.serval.com` | `https://public.api.serval.com/mcp/` | | `app.eu1.serval.com` or `.eu1.serval.com` | `https://public.eu1.serval.com/mcp/` | The US server URL sends EU organizations to `app.serval.com` for approval, where they cannot sign in. See [Data residency](/sections/documentation/platform/data-residency) for details on regions. ### Connect your AI tool Your organization admin may have already added Serval as a connector. Check **Settings > Connectors** to see if it's available. If you need to add it yourself: 1. Go to **Settings > Connectors** 2. Click **Add custom connector** 3. Enter a name (e.g., "Serval") and the server URL for your region: ``` https://public.api.serval.com/mcp/ ``` EU organizations use `https://public.eu1.serval.com/mcp/` instead. 4. Your browser will open to approve access to your Serval account 5. After approval, Serval tools are available in your conversations Custom connectors require a Pro, Team, or Enterprise plan. Add the following to your Claude Desktop config file: * **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` * **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` ```json theme={null} { "mcpServers": { "serval": { "command": "npx", "args": ["-y", "mcp-remote", "https://public.api.serval.com/mcp/"] } } } ``` EU organizations replace the server URL with `https://public.eu1.serval.com/mcp/`. Restart Claude Desktop. On first use, your browser will open to approve access. Node.js v18+ is required. Install it with `brew install node` (macOS) or `winget install OpenJS.NodeJS` (Windows) if you don't have it. Any AI tool that supports MCP can connect to Serval. Set the server URL for your region: ``` https://public.api.serval.com/mcp/ ``` EU organizations use `https://public.eu1.serval.com/mcp/` instead. Your client will discover authentication endpoints automatically and open your browser to approve access. *** ## Approving Access The first time your AI tool connects, your browser will open an approval page. Click **Approve** to grant access. Your AI tool can only do what you can do in Serval — it uses your account and permissions. You won't need to re-approve unless you revoke access or your token expires. *** ## What You Can Ask Once connected, just talk to your AI assistant naturally. For example: * "Create a ticket — I can't connect to VPN" * "What's the status of my laptop request?" * "Show my pending access requests" * "Update my ticket to say I've restarted the router" If your role includes running workflows (team contributors and above), your assistant can also find and run them directly — for example, "Run the software license request workflow for Figma." Workflows that require approval still go through their normal approval process — your assistant starts the request, and approvers are notified as usual. Your AI assistant uses your account and permissions, so it can only access your own tickets, requests, and data. The available actions depend on what your organization has configured. *** ## FAQ No. Any Serval user can connect their AI tools. You'll use your own account and permissions. The Serval MCP server is included with your Serval plan. You'll need your own AI tool subscription (e.g., Claude Pro). No. Your AI tool has the same access you do. It cannot see tickets or data that you wouldn't normally have access to. Remove the Serval configuration from your AI tool's settings. This immediately stops the connection. MCP (Model Context Protocol) is an open standard that lets AI assistants connect to external services like Serval. *** ## Troubleshooting Node.js is not installed or not visible to Claude Desktop. Install it globally (`brew install node` on macOS), then restart Claude Desktop. Check MCP logs on macOS: ```bash theme={null} tail -n 50 ~/Library/Logs/Claude/mcp-server-serval.log ``` Common causes: expired token or network issue reaching `public.api.serval.com` (or `public.eu1.serval.com` for EU organizations). Your AI tool is configured with the US server URL. Change it to `https://public.eu1.serval.com/mcp/` and connect again. The approval page then opens on `app.eu1.serval.com`. The same applies in reverse: a US organization configured with the EU server URL is sent to `app.eu1.serval.com`, where it cannot sign in. *** ## Related Technical details and full tool list Other ways to get help through Serval # Slack for Users Source: https://docs.serval.com/sections/documentation/end-user/slack-quickstart Quick-start guide for getting help from Serval in Slack ## Quick Start Serval provides AI-powered help desk support directly in Slack. Choose any of these methods to create a ticket and start a conversation with Serval: **Use from anywhere in Slack** Type `/serval help` followed by your request in any channel or DM: ``` /serval help I need access to the AWS production account ``` This works anywhere in Slack as long as Direct Messaging is enabled by your Serval administrators. **Turn any message into a ticket** 1. Hover over any Slack message 2. Click the **...** (three dots) menu 3. Select **"Create a ticket"** using Serval Perfect for when someone describes an issue in a message and you want to track it without asking them to retype it. **Use your team's support channel** If your organization has configured helpdesk channels (like `#it-support`): 1. Go to the helpdesk channel 2. Start a new thread with your request 3. Serval automatically responds and creates a ticket No need to tag @Serval - it monitors all new threads in helpdesk channels. Each of these methods will create a ticket for your IT request and start a conversation with Serval to help resolve your issue. *** ## Having a Conversation with Serval Once Serval responds to your ticket, you can have a natural conversation: ### What You Can Do * **Ask follow-up questions**: "What is the latest status of this request?" * **Update status**: "This is resolved now, thanks!" * **Share files**: Drag screenshots or logs directly into the thread * **Mention teammates**: Tag others if they need to be involved ### Keep It in the Thread * **Reply in the same thread** for follow-ups on the same topic * Serval remembers the full conversation context * Your support team can see what's been discussed If you mention another person, Serval will step back to allow for discussion. Tag `@Serval` so it knows to re-engage! ### Track Progress Watch for emoji reactions on your messages: * ⏳ Serval is working on it * ✅ Successfully completed * ❌ Cancelled Serval also updates the status in each Slack thread, and includes a ticket link so that you can see full details in the Serval web interface if needed. *** ## Tips for Best Results Include key details right away: error messages, usernames, system names, what you've already tried. **Example:** "I'm getting 'Invalid credentials' when logging into the customer portal with [john@company.com](mailto:john@company.com)" Create separate tickets for different problems. This helps tracking and makes it easier for your support team. Keep all conversation about one issue in the same thread. Serval and your support team maintain full context this way. No special commands needed - just explain your issue as you would to a colleague. *** ## Want to Learn More? Complete reference for all interaction methods, thread management, workflows, and advanced features For administrators: How to configure Slack channels, Team Inbox, and integration settings ## Related Documentation * [Comprehensive Guide to Slack](/sections/documentation/helpdesk/interacting-with-serval-in-slack) - Complete reference with advanced features * [Ticketing Overview](/sections/documentation/ticketing/overview) - Understanding the ticket system * [Slack Integration](/sections/integrations/slack) - Setup and configuration for administrators # Submit a Request Source: https://docs.serval.com/sections/documentation/end-user/submit-request How to create tickets and get help from your IT, HR, or support teams As an employee, you can submit requests to get help from your organization's support teams. Serval makes it easy to ask for what you need in plain language—no forms or ticket numbers required. *** ## Ways to Submit a Request Submit requests through whichever channel your organization has enabled—Serval routes everything to the same ticketing system regardless of source. See all available channels and how to configure them *** ## Submitting a Request in Slack or Teams The fastest way to get help is through your messaging platform. Simply message the appropriate support channel with your request. The experience is the same in Slack and Microsoft Teams. Look for channels like `#it-help`, `#hr-requests`, or `#facilities`. Your organization may have different channel names. Write your request in plain language. Be specific about what you need and include any relevant details. **Good examples:** * "I need access to the Figma design files for the marketing team" * "My laptop is running slow and apps keep crashing" * "Can I get a standing desk for my home office?" Include context like urgency, deadlines, or who else is affected. This helps your support team prioritize. Serval will acknowledge your request and may: * Resolve it automatically using available information or workflows * Ask clarifying questions to better understand your needs * Route it to the right team member if human assistance is needed You'll receive updates in the same thread. You can also view all your requests at app.serval.com. *** ## Submitting a Request in the Web App You can also submit requests directly at app.serval.com. When **Home** is enabled for your organization, it replaces **New request** in personal and global navigation. If you can create tickets, start and send a request under **What do you need help with?** on Home. Use the request editor and team picker, and select a team to attach files. The **Access**, **Service Catalog**, and **Knowledge** shortcuts sit below the editor and follow your permissions and organization settings. Ongoing issues and journeys appear next. Your **My tickets** and **Assigned to me** tabs appear beside approvals and Inbox updates on wide screens. On narrow screens, approvals and Inbox updates appear before your tickets. Active journey progress refreshes while you view Home, and completed journeys leave the overview after the next refresh. When Home isn't enabled, **New request** keeps its existing page or dialog behavior. The separate request-dialog feature controls that choice and team ticket creation. Enabling Home doesn't enable that dialog or change the existing request page's catalog options. Home keeps its own request draft. Log in with your company credentials. Open **Home** where enabled, or **New request**. You have two options: * **Describe your request**: Type what you need in the chat input using plain language. You can attach files, @mention users, add checklists, and insert tables. * **Attach files**: Click the attachment icon to upload files relevant to your request (screenshots, documents, spreadsheets, or any other file type) * **@mention users**: Type `@` to mention specific people who should be aware of your request * **Insert tables**: Use standard Markdown pipe syntax (`| Column | Column |`) to create structured tables in your request * **Browse the Catalog**: Select **Browse Catalog** to choose from predefined catalog items. Pick **Access** to request role-based access to applications, or **All Services** to browse catalog items like new laptop orders, software installations, or other structured requests. Serval automatically routes your request to the right team based on your message. You can also manually select a team from the dropdown. If you're viewing a specific team's tickets, that team is pre-selected for you. Your request is created and you can track its progress in the web app. Use the Catalog when you know the type of request you need. Catalog items provide structured forms that capture the right information upfront, which helps your support team resolve requests faster. *** ## Tips for Faster Resolution Include details like application names, error messages, or dates. The more context, the faster the resolution. Submit separate requests for unrelated issues. This helps teams track and prioritize effectively. Respond promptly when Serval or a team member asks follow-up questions. IT issues go to IT channels, HR questions to HR channels. This ensures your request reaches the right team. *** ## What Happens Next After you submit a request: 1. **Serval analyzes your request** - AI determines the type of request, priority, and which team should handle it 2. **Automatic resolution** - For common requests, Serval may resolve it immediately using knowledge base articles or workflows 3. **Human escalation** - Complex issues are assigned to a team member who will follow up with you 4. **Resolution** - You'll be notified when your request is complete You'll receive all updates in the same place you submitted your request—the same thread, email chain, or web app view. *** ## Creating Standard Tickets for Testing Team members can create standard help desk tickets (instead of internal execution tickets) for testing purposes. This is useful when you want to verify how the help desk agent handles a specific request—the ticket flows through the same routing, AI triage, and workflow logic that an end user's request would. *** ## Viewing Your Requests To see all your submitted requests: 1. Go to **app.serval.com** 2. Click **My Requests** in the navigation 3. View status, updates, and history for each request # Microsoft Teams for Users Source: https://docs.serval.com/sections/documentation/end-user/teams-quickstart Quick-start guide for getting help from Serval in Microsoft Teams ## Quick start Serval provides AI-powered help desk support directly in Microsoft Teams. You can post in your team's support channel, summon Serval in a Silent Mode channel, and make a private request in DM. Each method creates a ticket for your request and starts a conversation with Serval to help resolve your issue. **Post in your team's support channel** In a Help Desk channel, post your request as a new message: ```text theme={null} Can you help me reset my password? ``` Serval responds automatically and creates a ticket. Serval monitors every new message in Help Desk channels, so you don't need to tag `@Serval` directly. If Serval doesn't respond, the channel may not be connected yet. An admin can add Serval and set the channel mode. For more information, see [Connect channels](/sections/integrations/microsoft-teams#connect-in-serval). **Summon Serval in a Silent Mode channel** In a Silent Mode channel, Serval files messages quietly and only replies when you ask. Mention `@Serval` to get a response: ```text theme={null} @Serval can you help me reset my password? ``` **Make a private request in a DM** For personal or sensitive requests, message Serval directly. Serval reads your message and routes it to a new or existing ticket. To create a ticket using an explicit form, type `/create-ticket` in your DM. Serval opens a short form where you describe your request, pick a team (or leave it on **Auto-detect** to have Serval automatically select the correct team), and choose who the ticket is for. ## Having a conversation with Serval Once Serval responds, you can have a natural conversation. ### What you can do * **Escalate ticket to a human**: Simply say "Escalate" * **Ask follow-up questions**: "What's the latest status of this request?" * **Update status**: "This is resolved now, thanks!" * **Share files**: Attach screenshots or logs directly in the conversation * **Trigger workflows**: "Run the new user onboarding workflow for [jane@company.com](mailto:jane@company.com)" (For more information, see [Workflows](/sections/documentation/workflows/overview)) * **Handle approvals and forms**: Serval provides interactive cards with buttons and fields directly in your chat ### Keep it in the thread For follow-ups on the same topic in a specific channel, reply in the same thread. Serval remembers the full conversation context, and your support team can see what's been discussed. If another person replies in the thread, Serval steps back to let the humans talk. Tag `@Serval` so it knows to re-engage. ### In direct messages Microsoft Teams doesn't support threads in direct messages, so a few habits help Serval route your messages to the right ticket: * **Explicitly signal a new request** **when you want a new ticket.** For example, New request: I need a license for Figma. * **Reference the existing issue** **when following up.** For example, Following up on my laptop replacement request. * **Reply with quote** **on the Serval message for the ticket you mean**. Useful for short follow-ups like "any update?" when several tickets are open. If your message could apply to more than one open ticket, Serval sends a card listing the tickets it thinks you mean, where you can select the right one or start a new ticket. ### Track progress * While Serval is working on an issue in a conversation, a typing indicator or a progress card shows that it's active. * Serval updates the ticket status in its messages and provides a ticket link. ## Tips for best results * Include key details like error messages, usernames, system names, and what you've already tried. For example: ```text theme={null} I'm getting 'Invalid credentials' when logging into the customer portal with john@company.com. ``` * Create separate tickets for different problems. This helps both Serval and your support team keep track of everything. * In a channel, keep all conversation about one issue in the same thread. * In a direct message, clearly signal when you're starting a new request so Serval doesn't fold it into an open ticket. * Explain your issue conversationally, as you would to a colleague. ## Related documentation * [Comprehensive Guide to Microsoft Teams](/sections/documentation/helpdesk/interacting-with-serval-in-microsoft-teams) - Complete reference with advanced features * [Ticketing Overview](/sections/documentation/ticketing/overview) - Understanding the ticket system * [Microsoft Teams Integration](/sections/integrations/microsoft-teams) - Setup and configuration for administrators # Track Your Requests Source: https://docs.serval.com/sections/documentation/end-user/track-requests View status updates and manage your submitted requests After submitting a request, you can track its progress, add information, and communicate with the support team. *** ## Viewing Your Requests ### In Slack or Teams If you submitted your request in Slack or Teams, all updates appear in the same thread: * Status changes (for example, **In Progress** or **Resolved**) * Messages from support team members * Requests for additional information * Resolution details Turn on notifications for the thread to stay updated on your request. ### In the Web App For a complete view of all your requests: 1. Go to **app.serval.com** 2. Navigate to **My Requests** 3. See all your tickets with current status Where enabled, **Home** replaces **New request** in personal and global navigation. Select **My tickets** on Home to review your requests. Use **Search tickets** or the filters to narrow the list, and scroll within the ticket list to load more results. Open a ticket to view its details or add a reply. On **Home**, select **View all** to open the full ticket list with the same **My tickets** or **Assigned to me** selection, search text, and filters. You can change or remove those filters in the full list without changing your saved Tickets view. When Home isn't enabled, Tickets continues to use your existing saved view. On **Home**, select **Ongoing issues** to view details for up to three active major incidents you have access to, with the most recently updated first. Select an incident card to open it. Ticket search and filters don't change this section. Resolved and canceled incidents no longer appear. *** ## Viewing Your Conversations with Serval Where your organization has enabled the personal help desk, the direct-message conversations you have with Serval in Microsoft Teams also appear in the web app under **Conversations**, next to **Tickets** in your personal sidebar. A conversation isn't a ticket. It's the ongoing chat you have with Serval, and it's where tickets get raised from. When Serval hands your request to a team, the resulting ticket appears next to the message that raised it, so you can jump straight to the request itself. Only tickets you have access to are shown. A ticket that no message in the conversation raised, such as one linked when Serval continued the conversation from a notification, appears at the top under **Tickets from this conversation**. ### One conversation, two places The web view and the Teams chat are the same conversation, not two copies of it: * **Messages you send in Teams**: appear in the web app. * **Messages you send in the web app**: appear in the Teams chat, so your history stays in one piece and Serval answers in both places. A conversation closes once it's been idle for a while. You can still read a closed conversation, but you can't reply to it. Message Serval in Teams to start a new one. *** ## Understanding Request Status Your request moves through different stages as it's being handled: | Status | What It Means | | :- | :- | | **New** | Your request was received and is awaiting review | | **In Progress** | A team member or Serval is actively working on it | | **Waiting on You** | The team needs more information from you | | **Resolved** | Your request has been completed | | **Canceled** | The request was closed without completion | Status names may vary depending on how your organization has configured their ticketing workflow. *** ## Connect an account to continue a request Some integrations, including external agents, need permission to act through your own account. When Serval asks you to connect an account, open the connection link and complete the authorization. If your request is still open and the AI agent is active, it continues automatically after you connect all the required accounts. You don't need to return to the ticket and send another message. This works for requests in the web app, Slack, Microsoft Teams, and WhatsApp, even if you close the authorization tab afterward. Automatic continuation is available for seven days after the workflow asks you to connect. It doesn't restart a resolved, canceled, archived, or deleted ticket, take over from a paused AI agent, or repeat a workflow you've already retried. If someone else posts or edits a reply while authorization is pending, automatic continuation stops; the original requester can send a new message to continue. Workflows you run outside a ticket still need to be run again after connecting. *** ## Adding Information to a Request If you need to provide more details or the team asks for additional information: ### In Slack or Teams Simply reply in the same thread where you submitted the request. Your message will be added to the ticket. ### In the Web App 1. Open your request from **My Requests** 2. Type your message in the conversation area 3. Send to add it to the ticket If you start a new thread or message instead of replying to the original, it may create a new request instead of updating the existing one. *** ## Common Actions Look for the SLA indicator on your ticket. This shows the expected resolution time frame based on priority. Higher priority requests are resolved faster. If your request is time-sensitive, reply in the thread or ticket and explain the urgency. Include details like: * Why it's urgent * What deadline you're facing * Who else is impacted The support team will adjust priority accordingly. If your issue resolved itself or you no longer need help, let the team know by replying "This is no longer needed" or "I figured it out, thanks!" The team will close the request. If your issue comes back after being marked resolved, reply to the original thread or ticket. The request will be reopened for the team to investigate. *** ## Getting Help Faster When the team asks for information, responding promptly keeps your request moving forward If you'll be out of office, mention it so the team can plan accordingly Screenshots, error messages, and specific details help the team resolve issues faster When asked for feedback, your response helps improve the support process # Create a form Source: https://docs.serval.com/sections/documentation/forms/create-a-form Describe a form to Catalyst, preview it live, and publish it to the service catalog. Catalyst chat on the left describing a laptop request form, with the form workspace on the right showing version v3 Published, the Check Laptop Stock workflow that runs inside the form, and a live preview of the laptop card grid ## Build it Go to **Service Management → Forms → New form**. Serval opens the **Create a new form** gallery with three ways to start: * Describe your form in the top **Create a form that…** box and let Catalyst build it (the path this guide follows). * Under **Or start from a working form**, pick a ready-made template such as a laptop request, expense claim, or discount approval. Each template comes with a working submit workflow, so you can submit the new form right away and edit it from there. * Choose **Create blank form** to open an empty **Untitled form**. Whichever you choose, Serval opens the workspace on your new form. Be specific about the questions, the options, and what happens on submit: > Create a laptop request form. Options should be MacBook Air, MacBook Pro 14-inch, Lenovo ThinkPad, and Dell Latitude, shown as cards with product photos. Require a business justification. Let people optionally say who it's for and when they need it. On submit, file an IT ticket with the chosen model. Keep talking to Catalyst: "make the justification field longer," "only ask for a manager if it's for someone else." Each change re-renders the preview. Name the form before publishing. The name is what employees see in the catalog and what the Help Desk Agent reads to decide the form fits a request. "Laptop Request" beats "IT Form 2." ## The workspace | Area | What it does | | :- | :- | | **Preview** | The real form, rendered by the real engine | | **Can be opened by** | Which employees may open and submit it. See [audience](/sections/documentation/forms/share-and-fill#control-who-can-open-a-form) | | **Runs inside the form** | Workflows called while the form is open, to fetch live data | | **Runs on submit** | The workflow that receives the answers | | **Version selector** | Switch versions, and see which one is published | | **Publish** | Deploys the current draft | | **Run history** | Every session, and the runs it started | | **Open in service catalog** | The published form, exactly as employees see it | | **Code (``)** | The form's source | ## Preview and publish The preview is a live session against your draft. Conditional fields appear, validation fires, and live-data workflows run. A preview submit runs the latest submit workflow **for real**, even as an unpublished draft. It doesn't publish your drafts, but side effects still happen: a ticket, provisioned access, a message. Edits autosave to a draft. The action bar shows **Unpublished changes** when your draft differs from what's live. Click **Publish** to deploy it. Publishing never disturbs a submission in progress. A session stays on the version it opened against. If a publish fails, the error names the problem in the code: an unknown option, an invalid icon name, a workflow reference that doesn't resolve. ## The code behind a form Catalyst writes it, and most builders never open it. It's under the `` button when you want it. ```tsx theme={null} import { view, field, Form } from "serval/forms"; import orderLaptop from "@serval/workflows/order-laptop"; export const main = view({ fn: () => { const [model, Model] = field.cards("model", [ { value: "mba", label: "MacBook Air (M-series)", description: "Lightweight macOS laptop for everyday work and travel." }, { value: "mbp", label: "MacBook Pro 14-inch", description: "High-performance macOS laptop for engineering and design." }, ], { label: "Choose your laptop" }); const [justification, Justification] = field.text("justification", { label: "Business justification", multiline: true, maxLength: 500, }); return (
); }, }); ``` * **`field.(key, …)`**: declares a question, returns `[value, Component]` * **`
`**: the root. `header` sets the title band, `submit` names the workflow, and `accent` / `density` pick the look * **Placement props**: `required`, `readOnly`, and `error` go on the component, not the declaration Because the value is an ordinary variable, logic is ordinary code: `{model === "mbp" && }`. Form code runs in a sandbox with no network, no filesystem, and no credentials. The only way it can cause work is by naming one of your workflows, and every call is re-authorized on the server. *** The field-type and validation reference. Conditional questions, live data, and the submit handler. # Fields and layout Source: https://docs.serval.com/sections/documentation/forms/fields Every field type a form can ask for, the validation each supports, and how to arrange them into sections. Describe the fields you want to Catalyst. This page is the reference for what's available. ## Field types | Field | Asks for | Submitted value | | :- | :- | :- | | `text` | Free text, single- or multi-line | The string | | `number` | A numeric value | The number | | `boolean` | A yes/no toggle | `true` or `false` | | `select` | One option from a list | The option's value | | `multiSelect` | Several options from a list | A list of values | | `cards` | One option from a visual grid | The option's value | | `date` | A calendar date | `"YYYY-MM-DD"` | | `time` | A time of day | 24-hour `"HH:MM"` | | `datetime` | A specific instant | RFC 3339 in UTC | | `duration` | A length of time | Whole seconds | | `attachment` | A file upload | The attachment ID | | `attachmentList` | Several file uploads in one field | A list of attachment IDs | | `entity` | One record from a [database](/sections/documentation/databases/overview) table | The record ID | | `entityList` | Several database records | A list of record IDs | | `user` | One person in your organization | The user ID | | `userList` | Several people | A list of user IDs | Every field takes a **label**, optional **help** text under the label, and a **message** that replaces the default error copy. ## Defaults Give a field a `default` when one answer is the usual one, such as a rehire-eligibility question that's normally yes. The field starts on that answer in Serval, Slack, and Microsoft Teams, and the default is submitted if the requester leaves it alone. Clearing a defaulted field counts as an answer, so it stays cleared. ```tsx theme={null} const [eligible, Eligible] = field.boolean("eligible_for_rehire", { label: "Eligible for rehire?", default: true, }); ``` | Field type | Default | | :- | :- | | `text` | A string | | `number` | A number | | `boolean` | `true` or `false` | | `select`, `cards` | One of the option values | | `multiSelect` | A list of option values | | `date`, `time`, `datetime` | Same format as the field's bounds | | `duration` | Whole seconds | | `user` | A user ID, usually the person filling the form in: `form.actor?.id` | | `userList` | A list of user IDs | A default has to be an answer the requester could give: one of the options, inside any `min` and `max`. A default that isn't fails at publish. Attachment and database fields don't take a default. Defaults are worked out each time the form updates, so a people field can start on the person filling it in: ```tsx theme={null} fn: (form) => { const [approver, Approver] = field.user("approver", { label: "Approver", default: form.actor?.id, }); ``` When nobody is filling the form in, such as an automatic prefill, `form.actor` is empty and the field starts blank. Make sure the default is someone the field's `filter` offers. Serval doesn't check it. ## Validation Serval enforces constraints, not the browser. A violation shows an error on the field and blocks submit on every surface. | Field type | Constraints | | :- | :- | | `text` | `format: "email" \| "url"`, `pattern`, `minLength`, `maxLength` | | `number` | `min`, `max` (inclusive) | | `date` | `min`, `max` as absolute dates: `"2026-03-01"` | | `time` | `min`, `max` as 24-hour times: `"17:30"` | | `datetime` | `min`, `max` as RFC 3339. A bound with no time zone reads as UTC | | `duration` | `min`, `max` in seconds. Write them as arithmetic: `30 * 86400` | | `multiSelect`, `entityList`, `userList`, `attachmentList` | `minItems`, `maxItems` | | `attachment`, `attachmentList` | `acceptedFileTypes`: MIME types, wildcards (`"image/*"`), or extensions (`".csv"`) | **Constraints never fire on an empty answer.** `required` owns emptiness. An optional field with a `maxLength` is checked only once somebody types in it. Date bounds are absolute. There's no "no earlier than today," because the form renders without a trustworthy clock. A rule that moves with the calendar belongs in the submit workflow. ## Choice fields `select` and `multiSelect` options can carry a `description` shown as secondary text. Slack truncates descriptions after 75 characters. The submitted value is unchanged. `cards` renders options as a grid of tiles with optional images: the right choice when somebody is picking a *thing*, like a laptop model or an office location. ```tsx theme={null} const [model, Model] = field.cards("model", [ { value: "mba", label: "MacBook Air (M-series)", description: "Lightweight macOS laptop for everyday work and travel.", imageUrl: "https://example.com/images/macbook-air.png", }, ], { label: "Choose your laptop", columns: 2 }); ``` Card images must be `https` URLs and load directly in the filler's browser. Serval doesn't host or proxy them, so use an image that's publicly reachable and expected to stay that way. `columns` accepts 2, 3, or 4 and defaults to 3. ## Database and user fields `entity` and `entityList` turn a [database](/sections/documentation/databases/overview) table into a searchable picker, so requesters choose real records instead of typing names that match nothing. You pick which field shows as the label, which is submitted as the value, and which appears as secondary text. Filters can key off *another field's current answer*, so choosing an application narrows the entitlements below it. `user` and `userList` pick from your organization: | Filter | Effect | | :- | :- | | `teamId` | Only members of that team | | `groupId` | Only members of that group | | `roles` | Only users holding one of the listed roles | | `includeDeactivated` | Include deactivated users. Off by default | `teamId` and `groupId` are mutually exclusive. Setting both fails at render time rather than dropping a filter. ## Layout | Element | Purpose | | :- | :- | | `Section` | Groups questions under a heading with an optional icon. `columns={2}` lays them out side by side | | `Notice` | A call-out. `tone` is `info`, `success`, `warning`, or `danger` | | `Divider` | A rule between groups | The `` root carries identity and look: `header` (title, subtitle, icon), `accent` (`brand`, `blue`, `green`, `yellow`, `orange`, `red`), and `density` (`comfortable`, `compact`). The accent colors the header band — it does not wash the whole form. ```tsx theme={null}
``` Colors and icons come from fixed lists, so forms match the rest of the product and render correctly everywhere, including Slack. An unrecognized name fails at publish instead of rendering nothing. *** Conditional fields and live data from your systems. Where forms appear and how each surface renders them. # Logic and workflows Source: https://docs.serval.com/sections/documentation/forms/logic-and-workflows Show fields conditionally, pull live data while the form is open, and hand the answers to a workflow. A form re-renders every time an answer changes, so it can ask different questions, fetch real data, and validate across fields before anything is submitted. Two kinds of workflow connect to a form, and the workspace shows both: | Workspace card | When it runs | What it's for | | :- | :- | :- | | **Runs inside the form** | While the form is being filled in | Fetching live data to show or shape the questions | | **Runs on submit** | Once, on submit | Doing the work the request asked for | ## Conditional questions A field's current answer is an ordinary value, so logic is ordinary code. No rule builder, no separate condition language. ```tsx theme={null} const [forSomeoneElse, ForSomeoneElse] = field.boolean("for_someone_else", { label: "Is this for someone else?", }); const [recipient, Recipient] = field.user("recipient", { label: "Who's this for?" }); return (
{forSomeoneElse && } ); ``` | Goal | How | | :- | :- | | Show a field only when relevant | Render it inside a condition | | Require a field only sometimes | `` | | Narrow one field's options by another | Filter the entity or user picker on the other field's answer | | Warn about a combination | Render a `` when it occurs | | Reject a combination | Set `error` on the field. A non-empty error blocks submit | Ask Catalyst for the behavior, not the code: "only ask for a manager when the request is for someone else." Then check it in the preview. ## Live data inside the form A form can call one of your workflows while it's open and render the result: stock levels, license counts, an employee's current device, a price. ```tsx theme={null} import { runWorkflowMemoized } from "serval/forms"; import checkLaptopStock from "@serval/workflows/check-laptop-stock"; const stock = runWorkflowMemoized(checkLaptopStock, { model }); return (
{stock?.outOfStock && ( That model is back-ordered until {stock.eta}. )} ); ``` * **Results are cached per set of arguments.** The call runs once for each distinct set. Change the selected model and it runs again. Change an unrelated field and it doesn't run at all. Calling it from the render is cheap, not a request per keystroke. * **The form stays usable while it's in flight**, then re-renders with the result. Query workflows should be read-only. They run whenever their arguments change, including in previews, so anything that creates or modifies belongs in the submit workflow instead. Every run a form starts, query runs included, appears under **Form activity**. ## The submit workflow ```tsx theme={null}
``` On submit, Serval validates every field, starts the workflow with your arguments, and moves the form to its submitted state. You pass an explicit `args` object rather than the whole form, so the workflow's inputs are a contract you control: rename a field without breaking the workflow, or pass derived values instead of raw answers. A form doesn't need a submit workflow. One without it collects and validates answers and stops there, which suits an acknowledgment or informational form. ## Safety Form code runs on Serval's servers in an isolated sandbox with no network access, no filesystem, and no ambient credentials. The only way a form causes anything to happen is by naming one of your team's workflows, and every call is re-resolved and re-authorized on the server. A form can never reach further than the workflows the team already has. ## Finding the forms attached to a workflow Open a workflow and look for the forms panel. It lists each form that calls the workflow and whether it does so while the form is open or on submit, so you can see the blast radius before changing it. *** Catalog, tickets, Slack, and audience control. Versions, run history, folders, and copies across teams. # Manage forms Source: https://docs.serval.com/sections/documentation/forms/manage-forms Versions, Form activity, folders, copies across teams, and taking a form out of service. ## The forms list **Service Management → Forms** shows the state of every form at a glance: | Column or badge | Meaning | | :- | :- | | **Name** | The form's name and folder | | **Fields** | How many questions it asks, and how many automations it's wired to | | **Last edited by** | Who last changed it | | **Never published** | Has drafts, never deployed. Employees can't reach it | | **Unpublished changes** | A version is live, but the draft differs | Search filters by name. Select several forms to publish, enable, disable, or delete them at once. Create folders and drag forms in, the same way you organize workflows. ## Versions Every publish creates an immutable version. Edits between publishes autosave into the current draft. * **Switch versions** from the version selector. The action bar says whether you're on the published version, the draft, or an older one * **Compare versions** to see what changed before publishing or restoring * **Restore an older version** to bring it back as a new draft. Restoring publishes nothing and deletes nothing Sessions are pinned to the version they opened. Publishing never changes a form out from under someone part-way through. ## Form activity **Form activity** lists every session opened against the form, newest first, with the workflow runs each one started. Use it to answer: did this submission start the workflow, which version was the requester on, and why did it fail? Click through for the workflow's own [run history and debugging](/sections/documentation/workflows/Run/run-history) view. ## Duplicate to another team Choose **Duplicate form**. Any team where you can manage forms. **Keep in the same folder** recreates the source's folder in the target team. Otherwise the copy goes to the top level. The copy arrives as an unpublished draft, so nothing is live until someone there publishes it. A copy references the same workflows the original did. Check the target team has the integrations and workflows the form depends on before publishing. ### Keeping copies in sync A cross-team copy stays linked to its source. * **On the copy**: a **Linked to** badge points at the source. When the source publishes a newer version, **Update Available** appears. **Pull update** brings it in as a new draft. **Ignore update** stops offering that version * **On the source**: a **linked forms** popover lists its copies, so you can see who's downstream before changing something Pulling writes a draft. It never publishes on the copy's behalf. ## Take a form out of service | Action | Effect | | :- | :- | | **Disable** | Stops new submissions and leaves the catalog. Versions stay intact, and enabling restores it exactly | | **Delete** | Permanently removes the form. Can't be undone | Disable first. It's the reversible way to stop a form that's producing bad requests, and it keeps the version and Form activity you'll want while diagnosing. ## Permissions | Capability | Who | | :- | :- | | Fill and submit the team's forms | Anyone in the organization, subject to the form's audience | | Create, edit, preview, publish, disable, delete | Team agents and managers | | Duplicate into another team | Requires manage-forms permission on the target team | See [Permissions](/sections/documentation/platform/permissions) for role assignment, and [Share and fill](/sections/documentation/forms/share-and-fill#control-who-can-open-a-form) to restrict who can open a given form. *** What forms are and when to reach for one. Build, preview, and publish end to end. # Forms overview Source: https://docs.serval.com/sections/documentation/forms/overview Build structured request forms that validate answers, pull live data, and hand a clean payload to a workflow. Forms collect structured information from employees and hand it to a workflow. Instead of a free-text ticket an agent has to chase down, a form asks the right questions, validates the answers, and starts the automation with a complete payload. Laptop Request form in a Serval ticket, showing a Device section with a two-by-two grid of laptop cards, each with a photo, name, and description ## Where forms live Forms live on a team, under **Service Management → Forms**. Serval left sidebar with Service Management expanded and an arrow pointing at the Forms entry ## Why Serval forms | Capability | What it means | | :- | :- | | **Built by describing them** | Tell Catalyst what to collect. It writes the fields, validation, and submit workflow. | | **Live data inside the form** | A form can run a workflow while it's open: check stock, look up a manager, price a license. | | **Conditional by default** | Fields appear, become required, or change options based on earlier answers. | | **Typed answers** | Dates, durations, uploads, database records, and Serval users are real field types with real constraints. | | **One form, every surface** | The same form renders in the catalog, in a ticket, and as a Slack modal. | | **Versioned like a workflow** | Edits autosave to a draft. Publishing deploys a version. Every version is restorable. | ## When to use a form | Use a form when | Example | | :- | :- | | A request always needs the same facts | Laptop request: model, justification, needed-by date | | Answers must be valid before work starts | Access request: a real system, a real role, a real expiry | | Questions depend on earlier answers | Onboarding: contractor or employee changes what you collect | | The requester picks from real data | A cost center, an application, a device from a database | Need only a parameter or two before running an automation? [Workflow inputs](/sections/documentation/workflows/Configure/inputs) may be enough. Reach for a form when the request has sections, logic, live data, and a lifecycle worth versioning. ## Lifecycle Describe the form to Catalyst, or edit its code directly. The preview is the real form, rendered by the real engine. From the catalog, a link, or because the Help Desk Agent offered it in their ticket. Every submission and its run appears under **Run history**. *** Build, preview, and publish your first version. Every field type, its validation, and how to lay out sections. Conditional fields, live data, and the submit handler. Catalog, tickets, Slack, and who can open a form. # Share and fill forms Source: https://docs.serval.com/sections/documentation/forms/share-and-fill Where published forms reach employees, how each surface renders them, and who's allowed to open one. Build a form once. Serval renders it wherever it's opened. ## The service catalog Every published, enabled form is a catalog item employees can find under **Browse Catalog**. From the workspace, **Open in service catalog** shows exactly what they see, and its link is stable enough to share directly or pin in a channel. The link is unavailable until the form has a published version, and while the form is disabled or you're viewing an older version. The tooltip says which applies. ## In a ticket, offered by the Help Desk Agent When somebody describes a request one of your forms handles, the Help Desk Agent opens that form in the ticket thread. The requester never has to know it exists. Slack thread where a user asks for a new laptop, a Request Summary shows ticket SENG-7015, and the Serval app replies with Fill out Laptop Request to continue and an Open form button The agent picks the form by name and description, so write both for a reader: "Laptop Request: request a new laptop from IT" tells the agent and the employee when it applies. The agent doesn't narrate the form, because the form is the message. Submitted answers come back into the ticket and the agent picks up from there. If the form fails to open, the agent reports the failure in a follow-up reply. The reply describes configuration problems without including internal error details. Temporary service failures are retried before the agent reports a failure. ## Slack modals **Open form** renders the form as a native Slack modal. Slack modal titled Laptop Request with a Device section, a Choose your laptop dropdown expanded to show four laptop options with descriptions, and a required Business justification text area Serval adapts the form to what Slack can do: | Aspect | In Slack | | :- | :- | | Live updates | Reactive fields update after a round trip rather than instantly | | Form length | Up to 50 fields fit a modal. Longer forms link out to Serval | | File uploads | Supported. The file-type filter is advisory: Slack filters by extension only. A multi-file field takes up to 10 files per upload, and a new upload replaces the files already attached, so a `minItems` above 10 is rejected when the form is defined | | Option descriptions | Shown as secondary text, truncated after 75 characters | | Styling | Accents and densities are Serval-only | Anything Slack can't render links out to the full form rather than dropping a question. For forms mostly filled from Slack, keep them short and the questions independent. Twelve fields with a couple of conditionals is a good Slack experience. Sixty fields will link out. ## Control who can open a form **Can be opened by**, in the workspace, sets the audience: * **Anyone in the org** (the default): every employee can find and submit it * **Selected access profiles**: only people matching those [access profiles](/sections/access-management/configuration/access-profiles) The gate covers every route to the form: the catalog, a direct link, and the set of forms the Help Desk Agent may offer. Someone outside the audience isn't offered it and can't open a link to it. The audience controls filling, not building. It has no effect on who can edit the form, and previewing your own draft is never gated, so you can always test a restricted form yourself. Setting the audience to **only** the built-in **Team Members** profile also makes each submission a **team-only** ticket — visible only to the team, not the wider help desk. Use it for confidential requests such as offboarding. (Adding any other profile alongside it opens the form more widely, so submissions stay regular help-desk tickets.) ## What the requester experiences * **Errors are specific**, on the field that caused them, in your wording * **Only relevant questions appear**, as they become applicable * **Progress survives a publish.** Someone mid-form finishes on the version they opened, never reset * **Submitting starts the work**, and the outcome appears where they filled the form ## Permissions | Role | Can do | | :- | :- | | Anyone in the organization | Fill and submit the team forms they're in the audience for | | Team agents and managers | The above, plus build, preview, publish, and manage forms | See [Permissions](/sections/documentation/platform/permissions) for role assignment. *** Versions, run history, folders, copies, disabling, deleting. Conditional questions and workflows that run inside the form. # Help Desk Agent Behavior Source: https://docs.serval.com/sections/documentation/helpdesk/agent-behavior Adjust Help Desk agent behavior, such as following up with quiet requesters Help Desk agent behavior settings let you fine-tune how the Help Desk agent handles specific situations. For example, you can control how the agent follows up with requesters who go quiet on a ticket. Help Desk agent behavior is different from channel configuration modes. Behavior settings determine how the agent acts and apply to an entire team. Channel modes control whether and how the agent engages in an individual channel (for example, **Help desk** or **Silent**). You set a mode for each channel. For more information, see [Channel configuration modes](/sections/integrations/slack#channel-configuration-modes). ## Adjust agent behavior To adjust behavior, navigate to your team settings and open **Help Desk Agent Behavior**. Behavior only applies to one team at a time. Only Team Managers can change Help Desk agent behavior settings. ## Set requester follow-ups When a ticket is waiting on the requester, the agent can remind them automatically and, after a set number of tries, close the ticket. Requester follow-up settings: the automatic follow-up toggle, time between follow-ups, maximum number of follow-ups, follow-up hours, and options to close the ticket after the final follow-up To enable this behavior, turn on **Automatically follow up with the requester**, then configure the following parameters: * **Time between follow-ups**: How long the agent waits before each reminder. Pick a preset duration or set a custom one. * **Maximum number of follow-ups**: How many times the agent reminds the requester before it stops. * **Follow-up hours**: Limit the time range in which the agent can send reminders. Set to **Any time**, or pick a [schedule](/sections/documentation/ticketing/ticket-configuration/schedules). A reminder that comes due outside the schedule's hours waits until the next window, and any remaining follow-ups continue from there. * **Follow up on escalated tickets**: By default, follow-ups only run on tickets the agent is handling. Turn this on to also follow up on tickets that have been escalated to a human, once a teammate's reply is waiting on the requester. * **Customize follow-up messages**: By default the agent writes each reminder itself. Turn this on to set your own wording for individual follow-ups. Each one can stay **AI-generated** or be switched to **Custom**, including the final follow-up. On escalated tickets, the agent considers recent internal notes before sending a reminder or automatically closing the ticket. If a teammate has recorded the requester's answer or that the team owns the next step, the agent can stop the follow-ups and leave the ticket open. This check also applies to custom reminders. The agent writes AI-generated reminders using public messages and the ticket's subject and description. ### Close the ticket after the final follow-up To close the ticket if the requester doesn't respond after the final reminder, turn on **Close the ticket after the final follow-up**, then set: * **Close as**: The status the ticket moves to when closed. Choose any status in the **Done** or **Canceled** group. * **Closeout message (optional)**: A message the agent posts to the ticket when it closes it. Leave it blank to close without a message. To apply your changes, select **Save**. # Help Desk Channels Source: https://docs.serval.com/sections/documentation/helpdesk/channels Configure the channels employees use to submit requests to your help desk Set up how employees submit requests to Serval by configuring your help desk channels. Each channel provides a different way for employees to reach your support teams. ## Configuring Channels To configure channels for a team: 1. Open your team in the sidebar 2. Go to **Settings** → **Channels** 3. Enable and configure your preferred channels *** ## Available Channels Private DM experience with your branded help desk agent. Employees can message directly, use slash commands, or post in designated help channels. Submit requests directly in Teams. Employees can chat with the Serval bot or use designated help channels. Accept requests via email. Configure in **Settings** → **Channels** → **Email** to set up your support email address. Customize auto-response messages per team or disable them entirely. Automatically available at [app.serval.com](https://app.serval.com). Employees can log in and submit tickets directly. *** ## Channel Comparison | Channel | Best For | Setup Required | | - | - | - | | **Slack** | Organizations already using Slack; quick, conversational support | Connect Slack integration | | **Microsoft Teams** | Organizations using Microsoft 365; seamless Teams experience | Connect Microsoft Teams integration | | **Email** | Traditional support workflows; external users | Configure email forwarding | | **Web Portal** | Self-service; users without Slack/Teams access | None (automatically available) | *** ## Recommended Setup Start with **Slack** or **Microsoft Teams** as your primary channel—whichever your organization uses most. Add email and web portal later as adoption grows. ### For Most Organizations 1. **Primary channel**: Slack or Microsoft Teams (based on your company's main communication tool) 2. **Secondary channel**: Web portal (always available as a fallback) 3. **Optional**: Email for users who prefer traditional support requests ### Multi-Channel Strategy You can enable multiple channels simultaneously. Serval routes all requests to the same ticketing system regardless of how they're submitted, so your agents see everything in one place. *** ## Email Configuration For detailed information on email intake, auto-responses, CC handling, subscribers, and sender trust, see the [Email guide](/sections/documentation/helpdesk/email). *** ## Slack Channel Options ### Team Inbox A private Slack channel where all tickets created for your team appear for triage. Two modes are available: * **Team Inbox** — All tickets for the team appear in this channel * **Team Inbox on Escalation** — Only tickets that are escalated to a human agent appear in this channel Choose "Team Inbox on Escalation" if you want to reduce noise and only surface tickets that need human attention. ### Private Internal Notes with Lock Emoji Members of the Serval team that owns a ticket can add a private internal note to it by replying in the ticket's Slack thread with a message that starts with the lock emoji (🔒). The message is stored on the ticket as an internal note: it is visible only to members of that Serval team and is not shared with the ticket requester. The leading lock emoji is stripped from the stored note. Keep in mind: * The lock emoji must be the first thing in the message. * It only works as a reply in the thread of an existing ticket. A top-level message starting with 🔒 creates a regular ticket, with the emoji left in the message text. * Only members of the Serval team the ticket belongs to can create internal notes this way. If the sender is not on that team, the message is added to the ticket as a regular message. * Serval controls visibility of the note within Serval, not within Slack. The Slack message itself remains visible to anyone who can see that Slack thread, so use this in team-only channels (such as the Team Inbox) rather than in channels the requester can read. ### Manual Escalation from Slack Escalate a ticket to a human agent directly from Slack without AI involvement. Use the manual escalation button on the ticket card in Slack to immediately route the ticket to your team's triage queue. *** ## Personal help desk in WhatsApp WhatsApp personal help desk is currently restricted to a controlled Serval internal text-beta cohort. It is not available for customer rollout. Within that cohort, the personal help desk can coordinate several requests in one WhatsApp chat. A conversation can create separate tickets for the appropriate teams, and their replies return to the same chat. Connect Twilio in your organization management team. Open the integration's **Help Desk** tab and use **Add number** in the **WhatsApp numbers** card. Each connected number shows its routing; use **Edit routing** on that number’s row to change it. Verification settings apply across the organization’s WhatsApp senders. Configure the sender's incoming-message webhook in Twilio. If the sender's routing dialog says WhatsApp personal help desk is paused, **Manage in settings** opens **Personal help desk** in organization settings. The shortcut appears only when Personal help desk settings are available to your organization. Saved routing takes effect when you enable the personal help desk and WhatsApp. Use **Enable personal help desk** to turn requests, follow-ups, and replies on or off for this number. Enabling a new connection requires an explicit routing choice, even when it retains teams from an earlier configuration. Choose **All Auto teams** to include every team marked Auto, including teams added later. For **Specific teams** routing, select **Add teams** to search for destinations. Selected teams appear in a scrollable list below the picker. Environment destinations include their workspace and environment names. Use the remove button to remove a team, then select **Save routing** to apply your changes. Removing a team also stops follow-ups to its linked tickets through this number. Then open **Personal help desk** in organization settings, turn on **Enable personal help desk** and **Enable WhatsApp**, and save. Return to the Twilio integration’s **Help Desk** tab. Organization admins configure verification in the **WhatsApp numbers** card. After you connect a number, the card shows **Sender identity verification**. Select **Challenge and verify** to configure **Start verification** and **Check identity**, or **Verify only** to run just **Check identity**. Both modes let you set **Maximum failed checks**. Select **None** to disable verification, then save your changes. Build Start and Check on Organization Management’s **Workflows** page. Choose enabled, deployed workflows that do not require form confirmation. Start must have no required inputs. Choose a **Failure destination team** before enabling verification. Search by team name in the picker; choose a standard or environment team in the same environment as Organization Management. Serval rejects a destination in another environment when you save. Approved internal participants need an active Serval account and a matching phone number on their profile. Deactivated accounts cannot use this channel. Send a test message to confirm both incoming messages and replies. A profile match alone does not enable access to the beta. **Challenge and verify** runs Start before prompting the sender. **Verify only** skips Start. When **Sender identity verification** is set to **Challenge and verify** or **Verify only**, your first message starts a challenge and Serval asks for the Check workflow's single required text input, such as a GMIN. Reply with that value; Check must finish within two minutes and return `{"verified": true}` only after confirming the claimed employee's identity. After success, Serval replies "You're verified. How can I help?" Send your support request again to start the conversation. The first message and verification replies are not added to support transcripts. Verification lasts 24 hours for that phone assignment across your organization's WhatsApp senders; an unfinished challenge expires after one hour and the next message starts a fresh challenge. If Start fails, Check is unavailable, or the sender reaches **Maximum failed checks** (three by default), Serval creates a human-support ticket with AI and creation automation disabled and notifies the sender. The ticket identifies the unverified sender and claimed employee, without their verification reply. Agents can reply over WhatsApp, but must verify identity before sharing employee information or taking action. Later inbound messages start a fresh challenge and are not appended to the handoff ticket. Reassigning a phone number blocks replies from its old handoff ticket. Changing or re-adding a phone number requires fresh verification. Disabling the policy bypasses verification without marking the number as verified. While verification is enabled, a number unknown to your organization creates a system-owned human-support ticket. Serval includes the messages, disables AI and creation automation, and tells the sender that a person will follow up. Later messages append to that open ticket; a message after it closes creates a new ticket. If you reopen an older ticket, new messages continue on the newest open ticket. When verification is off, unknown numbers receive no reply and create no ticket. It does not link the number to an employee or grant verification. The **Failure destination team** receives tickets for failed verification, unavailable verification workflows, and unknown senders. That team's custom escalation workflow, configured in **Assignment** preferences, runs on each new handoff ticket. These tickets have a system requester; the claimed employee's identity is unverified. Other creation automation stays disabled. As a defensive fallback, if an existing destination belongs to a different environment from the receiving WhatsApp connection, Serval creates the ticket in the connection team and uses that team's escalation workflow. Changing the destination does not move existing tickets or interrupt unknown-sender follow-ups. Check must be an enabled, deployed workflow in the organization management team with exactly one required string parameter and no form confirmation. Its field label determines the prompt, falling back to the field name. Verification values are passed directly to the workflow and are not stored in the help desk database. Workflow-service input retention is separate. This beta supports text messages. Use the ticket link to upload files, complete forms, or review workflow approvals. WhatsApp feedback prompts are not supported. Serval can send freeform replies within 24 hours of your latest message. A reply that arrives later waits until you send another message. *** ## Channel-Specific Guides Complete guide to configuring Slack channels, DMs, and slash commands End-user guide for all Slack interaction methods Complete guide to configuring Teams channels and DMs End user guide for all Teams interaction methods *** ## Next Steps After configuring your channels: 1. **Test each channel** — Submit a test request through each enabled channel 2. **Train your team** — Share the [End User Guide](/sections/documentation/end-user/end-user-guide) with employees 3. **Monitor adoption** — Check which channels employees prefer and adjust accordingly *** ## Welcome Message Template Below is a template your admin can customize and send to employees when introducing Serval: Admins: Copy and customize this message for your Slack announcement or email. ```markdown theme={null} 🎉 **Welcome to the Serval Help Desk!** We've upgraded how you get help at [Company Name]. Meet Serval—your new AI-powered assistant for IT, HR, and Operations support. **How to get help:** • **DM the Serval bot** directly in Slack for private requests • **Type `/serval help [your question]`** from anywhere in Slack • **Post in #[help-channel-name]** for general questions **What you can ask:** • IT: Password resets, software access, equipment issues, VPN help • HR: Benefits questions, PTO policies, payroll inquiries • Ops: Office access, travel booking, expense questions **What to expect:** ✨ Instant answers for common questions 🤖 Automated handling of routine requests (like access provisioning) 👋 Seamless handoff to a human when needed **Tips for success:** • Be specific—include app names, error messages, or deadlines • Keep conversations in the same thread • Watch for emoji reactions (⏳ = working, ✅ = done) Questions about Serval itself? Just ask! Type `/serval help How does Serval work?` Happy to have you on board! 🚀 — The [IT/Support/People Ops] Team ``` *** ## Need More Help? If you're having trouble using Serval or have feedback, reach out to your IT team or ask Serval: "How do I report an issue with Serval?" # Email Source: https://docs.serval.com/sections/documentation/helpdesk/email How email intake, composing replies, subscribers, CC handling, and guest access work in Serval Each team in Serval can have its own email intake address (e.g., `support@yourcompany.com`). When someone sends an email to that address, Serval creates a ticket, threads replies into the right conversation, and can automatically respond — depending on your team's settings and whether the sender is trusted. This guide covers how email intake works, when Serval responds, how to compose email replies, how subscribers and CC recipients are managed, and how external users are handled. *** ## How email intake works When someone sends an email to your team's intake address, Serval processes it as follows: 1. **The email is received** and scanned for viruses. 2. **Serval checks whether this is a new request or a reply** to an existing ticket. It uses standard email threading headers (`References`, `In-Reply-To`) to match replies to the correct ticket. 3. **If it's a new email**, a ticket is created and the sender becomes the ticket requester. 4. **If it's a reply**, the message is added to the existing ticket conversation. 5. **An auto-response** is sent to the sender confirming the ticket was created (if enabled). Serval intelligently threads email replies — including replies from CC'd users — back to the correct ticket. No duplicate tickets are created from replies. On messages linked to email (inbound or outbound), Serval shows inline **From**, **To**, and **Cc** routing in the thread. Matched org users and your intake address are labeled; other addresses show as email. Long lists can expand and collapse. *** ## When Serval responds How Serval responds to an inbound email depends on two things: whether the sender is **trusted** and whether the email is a **new request** or a **reply** to an existing ticket. ### Sender trust A sender is considered **trusted** when both of these are true: 1. Their email domain is in your team's domain allowlist. 2. The email passes [DKIM verification](https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail) (proving it actually came from that domain). If either condition fails — or if the sender's domain is not allowlisted but your team has **Allow all domains** enabled — the sender is treated as **untrusted**. Optionally, a team can also trust **organization members from any domain**. When that setting is on, an email from the address of an active member or admin of your organization counts as trusted even if the domain isn't allowlisted. The message must still pass DKIM or DMARC verification. Guests never qualify, and the sending address must match the member's Serval email exactly. ### Response behavior by scenario | Scenario | AI responds? | Auto-response sent? | What happens | | - | :-: | :-: | - | | **Trusted sender, new ticket** | If applicable | Yes (if enabled) | Serval creates a ticket with AI active. The AI may respond if it has a helpful answer. A confirmation email is also sent if auto-response is enabled. | | **Trusted sender, reply** | If applicable | No | The reply is added to the existing ticket. The AI processes the new message and may respond. | | **Untrusted sender, new ticket** | No | Yes (if enabled) | Serval creates a ticket but immediately escalates it to a human agent. The AI does **not** respond. A confirmation email is still sent if auto-response is enabled. | | **Untrusted sender, reply** | No | No | The reply is added to the existing ticket and synced to connected channels (e.g., Slack), but the AI does **not** respond. A team member needs to reply manually. | ### What "AI active" means Each ticket has an **AI active** flag that controls whether Serval's AI agent processes new messages and generates responses. * **Trusted sender tickets** start with AI active. * **Untrusted sender tickets** start with AI inactive and escalated to a human. * When a team member **escalates** a ticket, AI is deactivated. * A team member can re-enable AI on any escalated ticket by mentioning **@Serval** in the conversation, or by manually toggling it. When AI is inactive, Serval still delivers messages to connected channels and notifies subscribers — it just does not generate an AI response. *** ## Email settings Each team's email channel has its own configuration. Navigate to **Team Settings** > **Channels** > **Email** to manage these settings. ### Trust and domain settings These settings control who can send emails to your team and how Serval treats those senders. | Setting | What it does | | - | - | | **Domain Allowlist** | Restricts which sender domains can create tickets. When "Allow all domains" is off, only emails from allowlisted domains are accepted. | | **Allow all domains** | Accepts emails from any sender, regardless of domain. Senders from non-allowlisted domains are treated as untrusted. | | **Trust organization members from any domain** | Treats verified emails from active organization members and admins as trusted, even when their domain isn't allowlisted. Useful for contractors or staff who joined your organization with an outside email address. Off by default. | **If you enable "Allow all domains"**, senders from non-allowlisted domains will **not** get AI responses. Their tickets go straight to your team's queue for a human to handle. Only senders from allowlisted domains with valid DKIM get AI responses. If your team relies on Serval to respond to email requests, make sure the sender's domain is on your allowlist. ### Reply and auto-response settings These settings control how Serval sends emails back to requesters. | Setting | What it does | | - | - | | **Auto-response** | Sends a confirmation email to the sender when a new ticket is created. Can be toggled on or off. | | **Custom auto-response** | Replaces the default confirmation message with your own. Author it as rich text or as raw HTML. | | **Email footer** | Appends a signature or disclaimer to the emails Serval composes on this channel: auto-responses, agent replies, and the ticket-created notice. Author it as rich text or as raw HTML. | | **Sender name** | Customizes the display name on outbound emails. | | **Reply-To address** | When set, outbound emails use this as the Reply-To header. When empty, Serval uses the automatic behavior: the intake address when sending from a custom From, otherwise omitted. | For the custom auto-response and the email footer, switch between **Rich text** and **HTML** authoring per channel. Rich text is a simple formatted editor. HTML mode keeps tables, inline styles, images, and links, so you can reproduce a formatted signature block. The footer isn't added to campaign or workflow emails, which compose their own body. In HTML mode, select **Preview** to check the rendered auto-response or footer. The preview displays the HTML after Serval processes it for email. Links and forms are inactive in the preview; check their destinations in a test email. The custom auto-response can include variables that Serval fills in per ticket. Insert them from the variable menu in the editor rather than typing them. Serval rejects a save that contains any other `{{...}}` token, so a mistyped variable is caught before it reaches a requester. | Variable | Expands to | | - | - | | `{{Name}}` | The requester's name. | | `{{Ticket-Link}}` | A hyperlink to the ticket. | | `{{Ticket-ID}}` | The ticket's short ID as plain text, with no link. | ### Subscriber settings These settings control how subscribers are managed based on email CC headers. | Setting | What it does | | - | - | | **Auto-subscribe email recipients** | On inbound email, adds To and Cc recipients as subscribers (provisioning guests for untrusted domains when needed). On outbound replies, CCs all ticket subscribers except the To recipient and the sender. | | **Auto-unsubscribe removed recipients** | On inbound replies, removes subscribers whose address is no longer in the latest To or Cc headers. | *** ## Subscribers A **subscriber** is anyone who receives notifications about activity on a ticket. There are several ways someone becomes a subscriber: * **Requester**: The person who created the ticket via email is automatically subscribed. * **Assignee**: The team member assigned to the ticket is automatically subscribed. Assignees **cannot** unsubscribe. * **Email To/Cc**: When **Auto-subscribe email recipients** is enabled, anyone in the To or Cc headers of an inbound email is automatically subscribed. * **Reply Cc**: When an agent sends a public reply on an email ticket, people added to the composer **Cc** line are subscribed and copied on the outbound reply; people removed from the prefilled Cc line are unsubscribed. Team agents and managers who can post a public reply can also copy someone outside your organization: type the address and select **Add \ as guest**. Serval adds them as an organization guest and subscribes them, with no invitation email sent. * **Manual**: Use the ticket's **Change subscribers** control to add existing org members, or type an external email to add them as a guest subscriber. Guests added this way are not sent an invitation email. ### Subscriber notifications Adding someone as a subscriber does not notify them or tag them. They are not alerted about being added, and they do not see past messages unless they open the ticket. They will only start receiving notifications on **future** activity on the ticket. ### Removing subscribers Any subscriber can be removed from a ticket, which stops all future notifications for that ticket. This removes **all** subscription reasons at once (requester, commenter, mentioned, etc.). The one exception: **assignees cannot be unsubscribed**. If someone is both the assignee and a subscriber for other reasons, removing them as a subscriber has no effect while they remain assigned. A removed subscriber can always be re-added later. *** ## CC handling ### Composing replies On email tickets, public replies show **To** and **Cc** above the message body (hidden for internal notes). **To** is the ticket requester (or the last inbound sender if the requester has no email). **Cc** is prefilled from subscribers except the requester and you. Editing **Cc** adds or removes subscribers relative to that prefilled list when you send; editing **To** changes the requester. The composer also shows which inbox the reply is sent **from**: its label and address, with the reply-to address on hover. A ticket connected to more than one intake inbox lists each. Outbound email goes to **To**. With **Auto-subscribe email recipients** enabled, all other subscribers are CC'd (except you and the To recipient). The composer Cc field controls who is subscribed; it does not override which subscribers receive the email. ### Auto-subscribe email recipients This setting changes behavior in both directions: **Outbound emails (Serval to external):** * All ticket subscribers are CC'd, except the To recipient and the reply sender. * Deactivated users are excluded. Addresses that do not resolve to an org user are skipped. **Inbound emails (external to Serval):** * Anyone in the To or Cc headers of an incoming email is automatically added as a subscriber. * Recipients from untrusted domains are provisioned as guests before subscribing (see [External users and guests](#external-users-and-guests) below). When **Auto-unsubscribe removed recipients** is enabled, subscribers not in the latest inbound To or Cc are removed on reply. ### Replies that leave off the requester If an inbound email reply leaves the ticket requester off both To and Cc, Serval ingests it as an **internal note** instead of a public reply. Only team members can see it, it isn't emailed to the requester, and their subscription stays unchanged. This keeps side conversations between agents off the requester-facing thread, much like private comments in tools such as Zendesk. ### BCC handling BCC recipients on inbound emails are **not** added as subscribers and are not visible to Serval. This is standard email behavior — BCC headers are stripped by the sending mail server before delivery. *** ## External users and guests When an email arrives from someone outside your organization, Serval handles them based on your domain allowlist: ### Trusted domains (allowlisted) If the sender's domain is in your allowlist and passes DKIM verification, they are created as a regular **organization member**. They have the same access as any other user in your org. ### Untrusted domains If the sender's domain is **not** allowlisted (and "Allow all domains" is on), they are created as an **organization guest**. Guests have limited access: * They can only see and interact with tickets they are associated with. * They cannot browse other tickets, teams, or internal data. * Their access is scoped to the specific conversations they are part of. This also applies to Cc'd recipients. If **Auto-subscribe email recipients** is enabled and an inbound email Cc's someone from an untrusted domain, that person is created as a guest and subscribed to the ticket. ### Mailing lists and forwarded email When emails arrive through mailing lists (e.g., Google Groups) that rewrite the From header, Serval looks for `X-Original-From` and `X-Original-Sender` headers to identify the actual sender. This ensures the ticket is attributed to the right person, not the mailing list address. *** ## Custom From Address (White-Labeled Email) By default, outbound emails from Serval show a sender address like `your-team@intake.serval.com`. You can configure Serval to send emails that appear to come from your own branded address — for example, `it@yourcompany.com` — so that end users see a familiar sender and your organization's domain. Verify your domain at the organization level in **Settings → Sender Domains**, then choose a **Custom From address** in each team's email channel settings. You need access to your domain's DNS provider to complete verification. ### Verify a sender domain 1. As an organization admin, open **Settings → Sender Domains**. 2. Enter the domain you want to send from, such as `yourcompany.com`, and select **Add domain**. 3. Expand the domain to see its DNS records. Copy the displayed names and values into your DNS provider. 4. Wait for the domain status to become **Verified**. Serval checks the records automatically; verification usually completes within an hour after you add them. Sender domain verification applies to your organization. Once verified, the domain is available to teams when they configure an email channel's From address. If you cannot access Sender Domains, ask your organization admin or Serval support for help. ### How it works Serval sends email through AWS SES. Every email has two "from" addresses: * The **visible From** — what your recipients see (e.g., `it@yourcompany.com`). This is what you're customizing. * A **hidden envelope sender** — used by mail servers for SPF checks and bounce routing. Without custom DNS records, this defaults to an Amazon SES address, which means your mail authenticates against Amazon's domain rather than yours. Under a strict DMARC policy, this can cause messages to be quarantined if a forwarder breaks the DKIM signature in transit. The DNS records below enable DKIM signing for your domain and SPF authentication for the `serval` subdomain used as the envelope sender. ### DNS records to add Copy the exact record names and values shown in **Sender Domains**. Serval generates two sets of records: | Purpose | Type | Where to add it | | - | - | - | | DKIM signing | Three CNAME records | Under `_domainkey` on the domain you registered, such as `._domainkey.yourcompany.com` | | Custom MAIL FROM authentication | One TXT record | On `serval.yourcompany.com` for a registered domain of `yourcompany.com` | | Custom MAIL FROM routing | One MX record | On the same `serval` subdomain, using the displayed mail server and priority | Add the DKIM records to the domain you registered, not to its `serval` subdomain. For example, registering `yourcompany.com` requires records at `._domainkey.yourcompany.com`, not `._domainkey.serval.yourcompany.com`. Check how your DNS provider handles the domain suffix before saving. The `serval` subdomain is used for the envelope sender and bounce routing. Recipients still see your chosen address, such as `it@yourcompany.com`, in the From field. ### Inbound email forwarding The DNS records above only affect outbound email. For inbound email — so that replies from end users reach Serval — you need to configure forwarding in your mail provider (e.g., Google Workspace): * Forward `it@yourcompany.com` → your team's Serval intake address (e.g., `your-team@intake.serval.com`) Your organization's existing MX record (pointing to Google Workspace or Exchange) handles delivery of inbound mail to your domain. The Serval intake address receives it via the forwarding rule you configure there. ### Enabling custom From in Serval After the domain is **Verified**: 1. Open the team's **Settings → Channels** and select its **Email** channel. 2. Edit **Custom From address** and enter an address on a verified domain, such as `it@yourcompany.com`. 3. Save the address and test an outbound email and an inbound reply. You need permission to manage the team's channels. If no verified domains are available, ask an organization admin to complete verification in **Sender Domains**. If the address is marked **Managed by Serval**, contact Serval support to change it. If your organization does not have the custom From controls, contact Serval support for setup help. We recommend testing in a sandbox team before enabling on your production team. *** ## Best practices With **Auto-subscribe email recipients** off, outbound replies go only to the To address. Enable it only when your workflow needs other subscribers CC'd automatically. You can still adjust the audience per reply with the composer Cc line. Rather than allowing all domains, maintain an explicit allowlist of trusted domains. This prevents spam and ensures only legitimate senders can create tickets. Add partner or vendor domains as needed. Before replying with sensitive information, check the composer Cc line and the subscriber list. With **Auto-subscribe email recipients** enabled, every subscriber is CC'd on the email—not only the addresses shown in Cc. Remove anyone who should not receive it before sending. External users from untrusted domains become guests with limited access. However, they can still see messages on tickets they are subscribed to. If a ticket contains internal-only information, remove external guests from the subscriber list before discussing it, or use internal notes instead of email replies. Configure Serval to send from your organization's email address (e.g., `it@yourcompany.com`) so recipients see a familiar sender. See [Custom From Address](#custom-from-address-white-labeled-email) above for the setup steps. # Microsoft Teams Source: https://docs.serval.com/sections/documentation/helpdesk/interacting-with-serval-in-microsoft-teams Complete reference for all interaction methods, thread management, and advanced features Serval integrates with Microsoft Teams, making it easy to create tickets, trigger workflows, and get help without leaving your conversations. This guide covers all the available interaction methods. Setting up Teams or configuring channels? See the [Microsoft Teams integration setup](/sections/integrations/microsoft-teams) guide for administrator instructions. ## Overview Post in a **Help Desk** channel and Serval responds automatically Private 1:1 chats. Serval routes your messages to the right ticket Trigger workflows, approve requests, and manage tickets ## Home and Tickets tabs Home and Tickets are available when the Microsoft Teams personal help desk release is enabled for your organization. They use the existing Teams sign-in configuration and don't request additional Microsoft Graph permissions. The tabs support Microsoft's commercial cloud. The tabs are part of the Teams app package: administrators add them by downloading the package again from the Microsoft Teams integration's setup page and uploading it in the Teams Admin Center under **Teams apps → Manage apps**. The package includes the tabs whenever the release is available for the connection, and carries a higher manifest version so Teams accepts it as an app update. To run without the tabs, keep the package you already uploaded, or remove the `serval-home` and `serval-tickets` entries from the manifest's `staticTabs` before uploading. **Chat** remains the app's first tab. **Home** and **Tickets** are separate tabs alongside Chat. Open **Home** for pending approvals, open requests, and assigned work, with shortcuts to each list and **New request**. **Needs your attention** shows requests waiting for your approval, including the requester, reason, and access duration. Select **Approve** or **Deny**; when a written reason is required, enter it before submitting. Approvals with rich review content open their full review page in Serval. **Recent requests** shows the latest public message, status, and assignee avatar, with profile photos when available. Short lists fit their contents, and longer lists scroll independently. Select **View all** under **Recent requests** to find your request history in Tickets, including resolved requests. Select **New request** to open **Chat** and describe what you need. Select the **Tickets** tab to open the ticket workspace: * **My requests**: View tickets you requested across Serval teams in your organization, including requests routed to another team. * **Assigned to me**: View your assigned tickets across Serval teams where you have permission to view tickets. * **Open**, **All**, and **Resolved**: Filter tickets by status. **Search tickets** matches ticket references and titles across your permitted ticket history, including older tickets. Select **Load older tickets** to see more results. Select a ticket to read its conversation and send a reply in the same page. Ticket rows show who requested the work in **Assigned to me**, and who is helping you in **My requests**. The ticket list and conversation scroll independently, with the reply box kept visible. If you have the corresponding team permissions, you can change **Status** or select **Internal note** to add a note visible only to the support team. Queue access restrictions still apply. Home and Tickets exclude archived, trashed, and deleted tickets. Conversation messages display Markdown formatting, including bold text, lists, links, quotes, code, and tables. Messages are left-aligned with sender names, profile photos when available, and timestamps. Internal notes have a lock badge. The Tickets composer supports text replies, including Markdown. Use **Chat** for new requests and attachments. Tickets with replies locked no longer accept public replies from Tickets. If Home isn't available, confirm that you're signed in to Teams with the account linked to your Serval organization and that your administrator has distributed the updated app package. ## Serval in channels Before Serval can respond in a channel, the Serval app must be added in Microsoft Teams and the channel must be configured in Serval. To do this, add the Serval app from the Teams app store (**Apps** → search for **Serval**), then `@mention` Serval in the channel, then set the channel mode on the **Help Desk** page of your Microsoft Teams integration. For more information, see [Connect channels](/sections/integrations/microsoft-teams#connect-in-serval). Depending on the type of channel or message, Serval interacts in different ways: * In **Help Desk** mode channels, Serval automatically monitors and responds to all new threads. * In **Silent Mode** channels, mentioning `@Serval` activates assistance for that thread. When Serval draws on web sources to answer, it cites the pages it referenced beneath its reply, in both channels and direct messages. ### Examples #### Get help in a Help Desk channel ```text theme={null} Can you help me reset my password? ``` #### Get help in a Silent Mode channel ```text theme={null} @Serval can you help me reset my password? ``` #### Trigger a workflow ```text theme={null} @Serval run the new user onboarding workflow for jane@company.com ``` ### Thread-based interactions #### Working within threads Serval maintains context within Teams channel threads, with the following benefits: * Keeps messages for a particular ticket in the same thread * Serval remembers context from earlier in the thread * You can ask follow-up questions While Serval is working on your request, a typing indicator appears in the conversation so you know it's active. ## Direct messages Your Serval administrator must enable direct messaging. This is configured within the Microsoft Teams integration at the team level. Any Serval administrator will be able to view your support ticket, but others in your organization won't. #### Private support conversations For personal or sensitive requests, message Serval directly. When an action needs a button or a form, such as an approval, Serval presents it as an interactive card within your DM. #### Attachments in the personal help desk Where your organization has enabled the personal help desk, you can send screenshots, documents, and logs directly in your Teams DM. Serval uses supported attachment contents to understand your request and choose the handling team, including when you send a screenshot without accompanying text. * **Screenshots**: PNG, JPEG, GIF, and WebP images are described for the help agent. * **Text and logs**: Serval reads UTF-8 text files, including plain text logs, CSV, JSON, XML, and Markdown. Long files are truncated in the agent's context. * **Documents**: PDF and Word (`.docx`) text extraction is available where document parsing is enabled. The personal help desk and the receiving team use their respective parsing settings. When Serval creates a team request or forwards your follow-up to an existing request, it can include the relevant original files. You don't need to upload them again. Only the files selected for that request are copied into its ticket; the rest of your personal conversation isn't shared with the team. You can send up to 10 files per message, each up to 50 MB. If a file can't be read, Serval can still forward a successfully uploaded original to the handling team. It may ask for a description when it needs more information to route the request. Files that fail download or upload checks aren't available for forwarding. #### How DM conversations are organized Microsoft Teams doesn't support threads in direct messages. Serval uses the contents of your messages to intelligently route to a new ticket, or an open ticket discussed earlier in the conversation. For best results in DMs: * Clearly signal a new request when you want a new ticket (for example, `New request: I need a license for Figma`). Alternatively, if Serval isn't handling the process correctly, you can use the [`/create-ticket` command](#create-ticket-command) to create the ticket explicitly * Reference the existing issue when you're following up (for example, `Following up on my laptop replacement request`) * Keep to one request per message where possible (for example, `Following up on the Figma license request` instead of `Following up on the Figma license request. Can you also check on my laptop replacement?`) * Provide enough context in each individual message (for example, existing ticket information) so that Serval can optimally route your request (for example, `Following up on Vercel license request` instead of `Following up on my ticket.`) * Avoid short, ambiguous responses to Serval (for example, if Serval responds with `Your laptop replacement has been sent. Should I close the ticket, or keep it open until you receive your laptop?`, responding with `Keep it open` is better than `Ok`) DM routing relies on understanding your messages in natural language. Currently, the process is less precise than channel threads, where each thread maps cleanly to one ticket. If you aren't getting good results in DMs, you can use a [**Help Desk** channel](#serval-in-channels) instead, where threading keeps each request separate. #### Specify a ticket in a DM with multiple requests When you have more than one request open in the same DM, use the reply with quote feature on the Serval message for the ticket you mean. Serval reads the quoted message, finds the ticket it belongs to, and routes your reply there instead of inferring the ticket from your text. This is useful for short follow-ups like "no" or "any update?" that wouldn't give Serval enough info to route. Usage tips: * If you quote more than one message at a time, Serval asks you to reply with a single quoted message so it knows which request you mean. * If the quoted message doesn't match a ticket Serval can steer to, Serval falls back to routing from your message text. * If the ticket is already closed or archived, Serval tells you it's no longer accepting replies rather than reopening it. #### When Serval asks which ticket you mean If your message could apply to more than one open ticket, Serval sends a card listing the tickets it thinks you might mean (up to three). In the card, you have a few ways to respond: * Select **Reply** on the ticket you meant. * Select **Create a new ticket** to start a fresh one. * Send a message with more information, such as the ticket number or what the request was about, and Serval routes from that instead. #### /create-ticket command In a direct message with Serval, select `create-ticket` from the command menu or type: ```text theme={null} /create-ticket ``` **When to use:** When you want to bypass Serval routing, and specify ticket parameters via DM. Serval responds with a short form where you enter your request details. If you belong to more than one team, the form also lets you choose which team the ticket should go to. Alternatively, leave it on **Auto-detect** to let Serval pick the team for you. You can also set who the ticket is for, which defaults to you. Once you submit the form, Serval creates the ticket and starts helping. `/create-ticket` is a direct-message command, and should be used in a 1:1 chat with Serval, not in a channel. In channels, post your request in a **Help Desk** channel or `@mention` Serval instead. ## Advanced interactions ### Workflow triggers Trigger [Serval workflows](/sections/documentation/workflows/overview) directly from Teams: * `Run the employee onboarding workflow for john@company.com` * `Execute the AWS access grant workflow for the engineering team` * `Start the offboarding process for the contractor anna@corporation.com` ### Approvals and access requests Serval handles approvals and access requests as interactive cards: * **Approvals:** When a request needs your approval, Serval sends a card with **Approve** and **Deny** buttons, along with an optional field to add a justification, to your direct messages. * **Access requests:** Request access to a system and Serval routes it through the appropriate approval workflow. * **Form inputs:** When a workflow needs more details, Serval collects information using a form. During the Teams dialog rollout, forms delivered through Conversations or the personal help agent offer **Open form** to complete them inside Teams. After submission, the card shows **Form submitted** and **View form**. Existing ticket-channel forms continue to use inline cards or a secure browser link. See [Forms in Teams](/sections/integrations/microsoft-teams#forms-in-teams) for availability and setup. ### Transfer tickets Move a ticket to another team by requesting the transfer: ```text theme={null} Transfer this ticket to the Security team ``` Only members of the ticket's current team can perform transfers. After the transfer, the receiving team takes ownership of the ticket. ### View and manage ticket status in Teams Serval displays dynamic ticket status directly in Teams messages. As a ticket progresses from creation to resolution, the status shown in Serval's message updates in real time, so you can track progress directly from within Teams. You can also update and manage tickets directly from a Teams channel or DM. For example: * `Set priority to high` * `Assign this to [teammate]` * `Close this ticket` * `Change status to in progress` ## Quick reference | Method | Where it works | Best for | | :- | :- | :- | | Message a **Help Desk** channel | **Help Desk** channels | Get assistance in a shared team channel. Serval responds automatically, no @mention needed. | | Use @Serval mentions | **Silent Mode** channels | Summoning Serval (since Serval doesn't respond automatically in **Silent Mode** channels) | | Reply to a thread in a channel | Channels with active threads | Continuing a conversation about an open ticket | | Send a direct message | 1:1 chat with Serval | Private or sensitive requests. Serval routes each message to a new or existing ticket. | | Use the `/create-ticket` command | 1:1 chat with Serval | Deterministically create a new ticket in a DM if intelligent routing misfires | | Reply with quote to a Serval message | 1:1 chat with Serval | Steering a follow-up to a specific existing ticket when several are open | ## Tips for success Include relevant details like user emails, system names, error messages, or links to help Serval take accurate action. In channels, keep related messages in the same thread so Serval maintains full context of the conversation. Serval understands conversational requests. No need for special syntax or formatting. ## Limitations Currently, the Serval / Teams integration has the following limitations: * No Team Inbox mode * No Team Only mode For a current capability comparison, contact [support@serval.com](mailto:support@serval.com). ## Troubleshooting ### Serval isn't responding 1. Is the Serval app added in Teams? (Go to **Apps**, search for Serval under **Built for your org**, and add it) 2. Is Serval added to the channel? (@mention Serval to add it) 3. Is the channel configured in Serval? (Check your Microsoft Teams integration settings) 4. Is the channel set to a mode other than disabled? (for example, silent or Help Desk) 5. Is your Teams organization properly connected to Serval? 6. Is your installation less than 24 hours old? ### /create-ticket isn't working 1. Make sure you're using it in a direct message with Serval, not in a channel 2. Type the full command, `/create-ticket`, and send it 3. Confirm direct messaging is enabled by your Serval administrator and that the Serval app is installed for your account 4. Refresh Teams (**Cmd/Ctrl** + **R**) 5. If the issue persists, contact [support@serval.com](mailto:support@serval.com) ## Related documentation * [Microsoft Teams Integration Setup](/sections/integrations/microsoft-teams) - Administrator configuration guide * [Ticketing Overview](/sections/documentation/ticketing/overview) - Understanding tickets * [Workflow Automation](/sections/documentation/workflows/overview) - Workflow documentation # Slack Source: https://docs.serval.com/sections/documentation/helpdesk/interacting-with-serval-in-slack Complete reference for all interaction methods, thread management, workflows, and advanced features Serval provides intuitive ways to interact directly from Slack, making it easy to create tickets, trigger workflows, and get help without leaving your conversations. This guide covers all the available interaction methods. ## Overview Type commands like `/serval help` from any channel or DM Create a ticket from an existing Slack message Tag @Serval in channels to activate assistance Continue conversations naturally in threads For support teams: Centralized view of all tickets Private one-on-one conversations with Serval ## Slash Commands ### /serval Command The quickest way to create a ticket from anywhere in Slack: ```text theme={null} /serval help [your request message] ``` **When to use:** At any time, especially when you prefer creating a quick & simple ticket. **Example - Access request:** ```text theme={null} /serval help I need access to AWS for today ``` The `/serval` command works anywhere in Slack as long as Direct Messaging is enabled by your Serval administrators. ## Message Actions ### Creating Tickets from Existing Messages Sometimes the perfect ticket description is already in a Slack message. You can turn any message into a ticket using Slack's message actions: 1. Hover over any message in Slack 2. Click the three dots (...) menu 3. Select "More message shortcuts..." 4. Choose "Create a ticket" using Serval from the list of actions **Benefits:** * No need to retype or copy/paste existing messages * Works on any message in any channel ## Mentions in Channels ### Activating Serval with @mentions In channels where Serval is present, you can activate help by mentioning @Serval: **How it works:** * In Help Desk channels: Serval automatically monitors and responds to all new threads * In Silent Mode channels: @Serval activates assistance for that thread * In Team Only channels: Behaves similarly to Help Desk channels, but does not escalate to a human. It will always stay engaged **Example - Getting help:** ```text theme={null} @Serval can you help me reset my password? ``` **Example - Triggering a workflow:** ```text theme={null} @Serval please run the new user onboarding workflow for jane@company.com ``` ## Thread-Based Interactions ### Working Within Threads Serval maintains context within Slack threads, making conversations natural and efficient: **Best practices:** * Keep related discussion in the same thread * Serval remembers context from earlier in the thread * You can ask follow-up questions naturally * Upload files, images, or logs directly in the thread ### Status Updates via Emojis Serval uses emoji reactions to communicate status at a glance: **Common status emojis:** * ⏳ Serval is working on it * ✅ Successfully completed * ❌ Cancelled ## Direct Messages (DMs) ### Private Support Conversations For sensitive requests, you can DM Serval directly: **When to use DMs:** * Personal or sensitive requests * Private troubleshooting sessions Your Serval administrator must enable Direct Messaging for this to work. This is done within the Slack application at the team level. Note that any Serval administrator will be able to view your support ticket, but others in your Slack workspace will not. ## Team Inbox Channels A dedicated private channel for Serval Managers and Agents to triage all tickets created for your team, without switching to the web interface. **Key benefits:** * Triage all tickets in one place, right from Slack * Collaborate with other agents on ticket resolution * Respond to end users directly—replies sync back to their original location Team Inbox channels are designed to be triage-only, meaning new messages posted to the channel won't create new tickets. Use `/serval help`, DMs, or help desk channels to create new tickets. ### Working with Team Inbox * **View**: Each ticket appears as a thread with details and history * **Respond**: Reply in threads—messages send to end users automatically * **Manage**: Use commands like `@Serval assign to me` to pick up and handle escalated tickets **Learn more:** For complete setup instructions, see [Configure Team Inbox Channels](/sections/integrations/slack#configure-team-inbox-channels). ## Advanced Interactions ### Workflow Triggers Trigger Serval workflows directly from Slack: **Example commands:** * "Run the employee onboarding workflow for [john@company.com](mailto:john@company.com)" * "Execute the AWS access grant workflow for the engineering team" * "Start the offboarding process for the contractor" ### Transfer Tickets by Tagging @Serval Move a ticket to another team by mentioning @Serval in a message and requesting the transfer. For example: ```text theme={null} @Serval transfer this ticket to the Security team ``` Only members of the ticket's current team can perform transfers. After the transfer, the receiving team takes ownership of the ticket. ### Manual Escalation Use the manual escalation button on the ticket card in Slack to escalate a ticket directly to a human agent without AI involvement. This bypasses the help desk agent entirely and routes the ticket to your team's triage queue. ### Ticket Management Update and manage tickets without leaving Slack: **Available actions:** * "Set priority to high" * "Assign this to @teammate" * "Close this ticket" * "Change status to in progress" ## Quick Reference | Method | Where it works | Best for | | - | - | - | | `/serval help` command | Anywhere in Slack | Quick ticket creation | | Message actions (...) | Any message | Converting existing messages to tickets | | @Serval mention | Channels with Serval | Activating help in a thread | | Thread replies | Active threads | Ongoing conversations | | Direct messages | Serval DM | Private requests | | Team Inbox | Team Inbox channel | Support agents triaging all team tickets | ## Ticket Status in Slack Serval displays dynamic ticket status updates directly in Slack messages. As a ticket progresses — from creation through workflow execution to resolution — the status UI in the Slack message updates in real time so you can track progress without leaving Slack. *** ## Welcome Message for New Users When a new user interacts with Serval for the first time in Slack, they receive a welcome message in the Messages tab introducing Serval's capabilities. This message explains how to get help, what they can ask, and where to find support. *** ## Tips for Success Include relevant details like user emails, system names, error messages, or links to help Serval take accurate action. Keep related messages in the same thread so Serval maintains full context of the conversation. Serval understands conversational requests - no need to use special syntax or formatting. Quick visual feedback helps you understand Serval's progress without reading every response. ## Troubleshooting ### Serval isn't responding **Check these common issues:** 1. Is Serval added to the channel? (Look for @Serval in the member list) 2. Is the channel configured in Serval? (Check your Slack integration settings) 3. For new channels, try @mentioning Serval to add it 4. Ensure your Slack workspace is properly connected to Serval ### Commands not working If slash commands aren't appearing: 1. Refresh Slack (Cmd/Ctrl + R) 2. Check that your workspace admin has approved the Serval app 3. Try typing `/serval` fully - it should auto-complete 4. Contact [support@serval.com](mailto:support@serval.com) if issues persist ## Related Documentation * [Slack Quickstart](/sections/documentation/end-user/slack-quickstart) - Quick-start guide for end users * [Slack Integration Setup](/sections/integrations/slack) - Administrator configuration guide * [Ticketing Overview](/sections/documentation/ticketing/overview) - Understanding tickets * [Workflow Automation](/sections/documentation/workflows/overview) - Workflow documentation # Simulations Source: https://docs.serval.com/sections/documentation/helpdesk/simulations Test how the Help Desk Agent handles realistic scenarios with safe, repeatable simulation runs Simulations are in beta and require the **Test & Release** capability. Enable it under **Settings → Capabilities**. If the capability is unavailable, ask your Serval contact to enable it for your organization. Simulations let you test how the Help Desk Agent handles realistic support scenarios without creating real tickets. Each simulation runs a saved scenario against your team's current configuration and records the full conversation, every tool and workflow call, and the outcome. Workflow calls and access requests are simulated by default, so nothing changes in your connected systems unless you explicitly allow it. For example, simulate a new hire asking for Figma access and verify that the agent routes the request for approval, without touching your real systems. To get started, open **Test & Release → Simulations** in your team sidebar. Simulation permissions let you read results, edit scenarios, run as yourself, or simulate other users independently. See [Permissions](#permissions). ## Browse simulations **Simulations** opens your suite library. Open a suite to see its configs, latest run health, and performance history. Use **New suite** to create a collection of configs that you can run together. Open a suite to browse its configs. Configs that don't belong to a suite appear under **Not in a suite** on the Simulations landing page; select **Review configs** to open their list. Suite and config searches cover the loaded rows; select **Load more suites** or **Load more configs** to include additional rows. ## Configs and runs A simulation *config* is a saved scenario: the requester, their opening message, the situation, and what a good resolution looks like. Every simulation runs from a config. Save a scenario once and re-run it any time to see how the agent's behavior changes as your team's guidance, knowledge, and workflows evolve. Each config keeps a revision history. Editing a config's scenario creates a new revision, and every run records the exact revision it executed, so past results stay comparable even after the scenario changes. A *run* plays the scenario against the Help Desk Agent on an isolated simulation ticket. Simulation tickets never appear in your Help Desk. By default, simulations use published skill and workflow revisions. When version pinning is enabled for your team, you can select other versions for an individual run. The simulation config itself must be published before you run it. ## Create a config From **Simulations**, select **New config**. This requires Catalyst access and opens a blank config editor beside a fresh chat. Fill in the scenario yourself, or describe what you want to test in the chat. Valid edits save to your Catalyst draft automatically. Opening the editor doesn't send a message or publish a config. The editor organizes the config into: * **Name** and **Description**: Edit these directly at the top of the editor, below the **Simulation config** banner. They describe how the config appears in the library and what it exercises. * **Simulation details**: Choose the **Requester**, write the **Opening message**, and provide **Scenario context** describing their situation and the details they can share. New configs default to a conversation with a simulated requester. Select **Run a single reply** to stop after the first agent response. * **Workflow configuration**: Choose which workflows can run live during a conversation. Single-reply simulations simulate workflows. See [Simulated and live workflows](#simulated-and-live-workflows). * **Judge criteria**: Provide an optional **Expected result** describing a successful outcome. When set, Serval scores each completed run pass or fail against it. In Catalyst, the top bar shows the config's **Draft** or **Published** status and its published revision when available. Select **Publish** when ready, or **Propose for review** if your team requires approval. Wait for changes to finish saving and complete required fields before taking either action. A review includes the pending change set from the chat, which may contain other resources. ### Edit a config Opening a saved config takes you directly to its Catalyst editor beside a fresh chat. Returning to a chat whose changes were published shows the current published config. Change the fields directly to update the staged draft automatically, or ask Catalyst to make changes. Historical comparisons retain the recorded scenario settings. Manual changes saved in Catalyst remain a draft until you publish them. If your team requires approval, select **Propose for review** in the config tab and publish the change set after approval. Hover over **Draft** in the top bar and select **Compare versions**. This read-only view uses the retained draft; newer edits appear after autosave completes. The current Catalyst **Draft** is available alongside published revisions, with the matching published revision selected for the before-and-after comparison by default. Use **Visual** to review the fields or **Code** for the full configuration diff. Comparing doesn't publish or change the config. ### Revision history Publishing scenario changes from Catalyst creates a new revision. Renaming a config or changing its description doesn't. In Catalyst, hover over the **Published** badge to see the revision's publication time and publisher, when recorded. Select **Full version history** in that popover to see published revisions alongside the editor. Select **Restore version** on an older version to stage its scenario as a draft, then publish it or propose it for review when ready. Wait for edits to finish saving before restoring. If the chat already has a saved draft, confirm before replacing its scenario. Existing history links also open Catalyst with the history panel visible. When at least two revisions have saved scenarios, select **Compare versions** in the version popover or history panel. Choose the base and comparison versions, or swap them. Published revisions store scenario settings only, so historical comparisons exclude name and description. Draft comparisons also include name and description when the published-state metadata is available. To delete a published config, open **More actions** in its editor and select **Delete config**, then confirm **Delete**. If your team requires review or you don't have permission to publish, the action is **Stage deletion** instead. The config stays available until an authorized user publishes the deletion, after any required approval. Past runs keep the revision they executed. ## Create and edit a suite From **Simulations**, select **New suite**. With Catalyst access, a blank suite editor opens beside a fresh chat. Enter a name and description and add configs, or ask Catalyst to help. Valid edits save to the staged draft automatically; select **Publish** when ready, or **Propose for review** if your team requires approval. Opening the editor doesn't send a message. Open a saved suite and select **Edit in Catalyst** to change its description or membership. You can review the proposed changes before publishing them. Without Catalyst access, the suite form lets you choose a name, description, and member configs directly. In either editor, configs already assigned to another suite are disabled and show their existing suite. Remove a config from that suite before adding it to another. The picker searches loaded configs; use **Load more configs** to browse further. You can save an empty suite and add configs later. Suites appear as a flat library, with their configs listed alphabetically. Select **Run suite** to run its saved configs together. Each run captures the config revisions it uses; later edits don't change past results. Open a suite run to see its performance summary, individual outcomes, and links to each config's simulation transcript. You can delete a published suite from **More actions** in its Catalyst editor. Confirm **Delete**, or **Stage deletion** if your team requires review or you don't have permission to publish. Deleting a suite keeps its configs and past runs. ### Suite dashboard Each suite page shows **Latest run** for its most recent finished launch within the latest 25 launches. Expected-result pass rate includes only simulations with a verdict. Expected-result misses, run errors, and unavailable scores remain separate. An active run shows its progress without replacing the last finished run's health. **Performance history** plots one pass-rate point per scored, finished launch across that same window. Select a point to open its run. Active launches and launches without scores appear as gaps; loading more entries in **Recent suite runs** doesn't change the chart's window. The **Latest run** header includes the run's timestamp, status, and a **View run** link. Open that run for individual simulation results and captured settings. The suite dashboard focuses on aggregate health and performance history; its config list shows the suite's current membership. ### Investigate run results Run results open in Simulations. With Catalyst access, **Open in Catalyst** opens the same result beside a chat, including while a run is queued or running and after it passes. Opening the run does not send a message or prepare an investigation prompt. For a finished run with an expected-result miss, an unresolved agent outcome, or an execution error, the action becomes **Investigate with Catalyst** and prepares an investigation prompt. Review the prompt and send it to begin. If the run is already open in Catalyst, the investigation action prepares the prompt in that chat. Catalyst can inspect the recorded member results, captured settings, transcripts, judge results, and workflow executions. It distinguishes expected escalation from unexpected non-resolution and suggests next steps. Investigating does not edit, publish, or rerun simulations. Missing scores or configs without an expected result do not trigger an investigation preset on their own; **Open in Catalyst** remains available. Results already shown beside a Catalyst chat omit the redundant open action. ## Run a simulation Open a suite and choose a config, or select **Review configs** under **Not in a suite** to find a config without a suite. The config opens in its Catalyst editor. Select **Run config** to open run options for the published revision shown in the editor. Publish any draft changes first. Review the settings, then select **Run simulation** to start an autonomous run and open its result page in Simulations. In run options, adjust **Live workflows** for this run or, when version pinning is enabled for your team, use **Test specific or unpublished versions** to choose workflow and skill versions. You can select a draft or an older published version. Pinning a workflow does not make it run live. **Reset to config** discards your overrides, and **Cancel** closes the dialog without starting a run. These changes never update the published config; the result records the effective settings under **Run parameters**. For an interactive run where you play the requester, open **Run options** beside **Run config** and select **Run interactively**. Choose any overrides, then select **Start interactive run**. An autonomous conversation ends when the issue is resolved, the agent escalates, or the conversation stalls. To change a scenario, edit and publish the config in Catalyst. For other one-off scenario variations, ask Catalyst to run it with overrides. Opening an old run-setup link takes you to the config editor without starting a run. If the run impersonates another user or allows live workflows, Serval asks you to confirm before it starts. ### Rerun a past simulation Open a finished config run from its config's **Run history**, then select **Rerun** on the result page. This starts a new run from the original config revision and saved overrides, including participants, conversation mode, live workflow selections, approval modes, and version pins. Later edits to the config don't change these settings. An interactive run starts a fresh interactive conversation. Rerunning doesn't replay the recorded conversation. Resources without version pins use their current published versions. Serval checks your current permissions and confirms impersonation or live workflows again before starting. ### Interactive runs In an interactive run, the run page shows the conversation as it happens. While the status is **Waiting for next turn**, type the requester's next message and select **Send reply**. Select **End simulation** to finish the run and score it. An interactive run left idle for two hours is marked **Stopped** automatically. ### Run a suite from a workflow Workflows can run a suite as one unit and wait for its result without polling. `serval.common.runSimulationSuite` starts every config in a published suite as a single suite run, pauses the workflow until that run is completed or failed, and returns the recorded run with its per-config verdicts and a `passed` flag. Use it when later workflow steps should wait for simulation results. A workflow runs with an API key or worker identity, so it does not confirm config revisions the way a person does; the suite's current published revisions run. Live workflows stay simulated unless the call sets `liveWorkflowsConfirmed`, and simulating other users still requires the permission to do so. ### Simulation concurrency limit Each team can have at most **50 running autonomous simulations**, shared across API keys, worker keys, user tokens, and service replicas. There is no minute, hourly, or organization-wide quota. Queued simulations do not count toward the limit. A suite can queue all of its configs and continues to execute at most five at a time. Each child waits for a team slot before starting if other simulations have filled the team's capacity. The concurrency limit does not restrict the number of configs in a suite. A direct simulation start at capacity, or while admission remains temporarily busy, returns **HTTP 429** (`resource_exhausted`) with a `Retry-After` hint in seconds. Retry after that delay, retaining the same `idempotency_key` when using a start endpoint. An idempotent retry reuses the existing run. Completed, failed, and stopped runs free their slots. Interactive sessions, Serval-internal evaluations, and reading results do not consume capacity. This limit controls concurrent execution; it does not impose a token or dollar budget. ## Simulated and live workflows By default, every workflow and access request the agent calls during a simulation is simulated. The agent sees a realistic mocked result and behaves as if the call ran, but nothing changes in your connected systems. To exercise specific workflows for real, select **Add workflow** under **Live workflows**. Workflows in this list may execute with real side effects. Every workflow you don't add remains simulated; leave the list empty to simulate all workflows. Live workflows run with access scoped to the requester, and you confirm the selection again before the simulation starts. Keep in mind: * Adding a workflow to the live selection requires permission to run published workflows (the **Contributor** role or above). * Only workflows that are deployed and enabled can run live. If a workflow in a saved config no longer qualifies, Serval blocks the run until you remove that workflow from the selection. * A workflow marked **AI-filled form** asks the requester for input. The simulated requester fills in the form from the scenario before the workflow runs. * Live calls happen as the conversation progresses. A live workflow that ran in an earlier turn can't be undone, even if you stop the run. ## Results Open a config's **Run history** or a suite's **Recent suite runs** to review a run in Simulations. Selecting an individual simulation from a suite opens its result page there too. **Open in Catalyst** or **Investigate with Catalyst** is an explicit handoff to chat; both show the same results, captured settings, and transcript beside the conversation. Opening results does not create a Catalyst conversation. For a suite run, ask Catalyst questions such as “Why was one item not resolved?” Catalyst reads the members and config revisions captured for that launch before inspecting an individual transcript. You can also ask for a suite's recent runs. A **Not resolved** outcome can still pass the expected-result check, for example when the scenario expects the agent to escalate the issue to IT. The run view groups the result, **Judge criteria**, **Conversation**, and **Run parameters** into sections. A completed run without an expected-result verdict shows **No verdict**; completion alone does not mean it passed. * **Status**: **Running *agent name*** while in progress, using your configured help desk agent name; **Waiting for next turn** during an interactive run; and then **Completed**, **Failed**, or **Stopped**. * **Outcome**: **Resolved** or **Not resolved**, with an AI-written summary of what happened and a confidence score. * **Expected result**: When the run has an expected outcome, a verdict shows whether the run met it. The verdict compares the meaning of the outcome, not its exact wording. * **Run parameters**: The config and revision the run executed, its mode, requester and other participants, opening message, scenario context, live workflow selections, and pinned versions. These are the settings captured for the run, so later config edits do not change the result view. * **Conversation**: The full transcript, rendered like a real ticket thread. Every tool and workflow call appears as a card labeled **live** or **mock** with its output. Each turn also shows the skills, workflows, knowledge, and access the agent considered. Select **Run history** beside **Run config** in a saved config’s Catalyst editor to see its past runs across all revisions. The popup shows execution status, judge results, revision, and timestamp. Use **Older** and **Newer** to page through runs; select a run to open its results in Simulations. Run history is available while editing an existing config, and closing it keeps your edits. Past results remain available through direct run links and suite history without Catalyst access; config creation and editing use Catalyst exclusively. ## Create a config from a real ticket To turn a real ticket into a repeatable test case, open the ticket's actions menu and select **Create simulation config from ticket**. Catalyst reads the ticket, derives the scenario from what happened, and saves it as a config with every workflow simulated. A ticket with more than one end user can't be turned into a config, because a config simulates exactly one requester. ## Ask Catalyst Catalyst can create, edit, run, and inspect simulation configs and suites for you. Ask in plain language, for example "run a simulation where a new hire asks for Figma access" or "re-run the VPN reset scenario and summarize what changed." Catalyst starts autonomous runs, waits for the results, and opens each run and config it touches so you can follow along. It asks for confirmation before running workflows live or simulating another user. You can start from **New config**, **New suite**, or a saved config or suite's edit action when you have Catalyst access. When a config is open beside the chat, Catalyst receives that config as context for your messages. Runs execute published config revisions. Unpublished simulation config or suite changes in a Catalyst chat are not part of a run; publish them before asking Catalyst to test those changes. ## Permissions | Action | Requires | | - | - | | View configs, suites, revision history, and run results | **Read simulations** | | Create, edit, or delete configs and suites | **Edit simulations** | | Run configs and suites where every simulated user is you | **Run simulations as yourself** | | Run a config or suite containing any other simulated user | Both **Run simulations as yourself** and **Run simulations as other users** | | Run workflows live inside a simulation | Simulation execution permission and permission to run published workflows | The libraries, dashboard, and Catalyst editors respect these permissions. Users with Read can inspect saved configs and results; authoring and execution controls require their respective permissions. Publishing also follows the team’s Catalyst review and publication policy. Assign Read alongside Edit or Run when someone needs to browse simulations and results. Edit does not grant permission to execute a scenario. A suite requires permission for every participant in every member config; Serval does not silently skip unauthorized configs. The default **Drafter** and **Contributor** roles include Read and Edit, but cannot run simulations. The default **Builder** and **App Builder** roles also include self-run access. The default **Manager** role also includes running as other users. These permissions can be assigned through custom team roles. Scoped API keys use `simulations:read`, `simulations:write`, `simulations:run`, and `simulations:run-as-others`. API keys have no personal identity, so running simulations requires both run scopes. Live workflows also require the existing workflow execution permission. For more on team roles, see [Permissions](/sections/documentation/platform/permissions). # Cross-team journeys Source: https://docs.serval.com/sections/documentation/journeys/cross-team A journey can hand out tasks to multiple Serval teams **Journeys is in open beta** and the product is actively evolving. A journey often spans more than one team. One team owns the journey, but its individual tasks can belong to other teams, so a single journey orchestrates work across HR, IT, Finance, and Facilities at once. For example, consider employee onboarding: An HR-owned onboarding journey can hand laptop provisioning to IT and badge access to Facilities. HR manages the process, and the journey tracks the whole thing end to end. ## How it appears in the overview On a cross-team journey, the **Journey Overview** shows one column per team involved. The owning team's column comes first, followed by a column for each other team that owns work. Journey Overview for a cross-team journey, showing one column per team involved Each team column shows the team's initials icon and name. When a column has multiple assignees, use its filter button to open a searchable menu. Select multiple people with the checkboxes to show their tasks together. **System** and **Unassigned** appear when those tasks exist. Clear the selections to show everyone's tasks again. Filtering keeps the team name visible and affects only that team's column. ## Access is per team Everyone involved sees the whole journey, but you act only on your own team's slice of it. You can only work on a task (e.g. submit its form, retry a run, open **Run Details**) in teams where you can manage journey tasks. In every other team's column, tasks are view-only: you can open them and follow progress, but you can't act on them. This keeps each team in control of its own work. IT owns the provisioning tasks, Facilities owns badge access, and neither can submit on the other's behalf, even though both watch the same journey move forward. ## Building cross-team journeys A journey builder assigns a task to another team, and that task then uses the other team's published workflows and runs inside that team. The task still belongs to the journey, so it shows up in the journey's overview and counts toward completion like any other task. The full mechanics (e.g. assigning a task's team, referencing that team's workflows, and routing the work) live in the [Building journeys guide](/sections/documentation/catalyst/journeys). ## Related What journeys are and how the pieces fit together Overview of journey tasks How admin and end users view journeys Design and build journeys in Catalyst # Monitor and manage journeys Source: https://docs.serval.com/sections/documentation/journeys/monitor-and-manage Track every journey from the team Journeys page, open a single journey, and manage its tasks **Journeys is in open beta** and the product is actively evolving. As an admin, you manage journeys from the **Journeys** page, which lists every journey for the team. The **Journey Overview** opens a single journey and its tasks. ## The team Journeys page Open **Journeys** in the team sidebar to see every journey for the team. It opens to the **All journeys** view, and you can save your own filtered views beside it. Use the search box to find a journey by name. The team Journeys page in the sidebar, listing journeys for the team ### Default columns The **All journeys** view shows these columns by default: | Column | What it shows | | :- | :- | | **Requested For** | The person the journey is for. | | **Journey Type** | The journey template this run came from | | **Due Date** | When the journey is due | | **Created At** | When the journey started | | **Completion** | How far along the journey is | | **Stakeholder** | The stakeholder(s) tied to the journey | | **Health Checks** | **No badge displayed -** Health check data isn't available yet. This is common for a new journey that hasn't started and has tasks with no due dates. **Passing -** The journey has at least one health check, and no tasks are failing, denied, or overdue. Checks that are running or don't yet have data don't block **Passing**. **Warning -** No failures, but one or more tasks in the journey are overdue. **Failing -** One or more tasks have failed or were denied. | | **Incomplete Steps** | The unlocked steps still open | | **Chats** | Active chats on the journey | ### Custom fields as columns Since journeys are a type of ticket, you can add custom fields such as location, department, or cost center. Any custom field on the journey ticket type can appear as its own column in the **All journeys** view. Add these columns to sort and filter on data beyond the defaults. You configure custom fields for journeys under **Settings → Ticket type → Journeys** ## The Journey Overview Select a journey to open its overview page. The journey overview shows every task categorized under the requester, stakeholders, and teams involved. Journey Overview showing tasks organized in columns by assignee across the requester, stakeholders, and teams > For more information, see [Admin and end user views](/sections/documentation/journeys/views). ### The ticket that started a journey When a journey is created by a workflow running on a help-desk ticket, the journey links back to that originating ticket: the journey heading shows a **Created from** link to the ticket, and the originating ticket lists the journeys it created in its details panel. Use these links to move between an intake request and the journey it kicked off. ## Manage tasks Select any [task](/sections/documentation/journeys/tasks) to open it. A task with subtasks expands to its steps, and each step opens to its own detail. ### Manage workflow runs When a task runs a workflow, its detail gives you controls for that run. Hover over the task to reveal them: A journey task on hover, revealing its run controls * **Run Details** opens the workflow run so you can see what happened. * **Retry** re-attempts a failed or canceled run after you fix the cause. * **Rerun** runs a finished workflow again from the start. > **Rerun** starts the workflow over from the beginning, and any actions it already took may happen again. ### Complete a manual task A manual task has no attached workflow, so the assignee completes it by hand. Use **Mark complete** to finish it, and **Reopen** to reverse that. > Only admins can mark a workflow-driven task done by hand. Its status follows the workflow. ### Open the underlying ticket Every task has an underlying ticket. Use **View Ticket** from the task to open it when you need the full conversation, custom fields, or history behind a step. ### Reading task status For more information, see [Task states](/sections/documentation/journeys/tasks#task-states) ## Related What journeys are and how the pieces fit together Overview of journey tasks How admin and end users view journeys Use a journey to manage tasks for a team The automations behind form and automated tasks Design and build journeys in Catalyst # Journeys overview Source: https://docs.serval.com/sections/documentation/journeys/overview Run multi-step, cross-team processes like onboarding and offboarding, with views tailored to everyone involved. **Journeys is in open beta** and the product is actively evolving. A *journey* is a multi-step, structured process built around the person at its center (e.g., a new hire being onboarded, an employee changing roles, someone leaving the company). Instead of a single ticket, a journey coordinates many tasks across many people, in the right order, over days or weeks. Everyone involved gets a view tailored to their role, so they see exactly the tasks that are theirs to do. ## When to use a journey Use a journey to manage a process when that process has one or more of these characteristics: * **Multiple tasks in a specific order**: steps that must happen in sequence, not all at once. * **Different inputs at different times**: information that's collected in stages rather than up front. * **Multiple stakeholders/teams**: work that's split across an employee, their manager, IT, and other teams. * **Time-based steps**: a task that shouldn't start until a certain date (for example, "send first-day instructions the morning they start"). * **Dependent tasks**: a task that can't begin until another one finishes, whether that earlier task has the same assignee or a different one. > If the process is a single thread of actions, a [workflow](/sections/documentation/workflows/overview) is usually the better fit. ### Example use cases Provision accounts, assign equipment, schedule training, and walk a new hire through first-week tasks. Revoke access, collect devices, and hand off responsibilities when someone leaves. Manage access, tooling, and the overall process for promotions or internal transfers. The example use cases are common in IT and HR operations, but a journey works for any structured, multi-step process your team owns. ## Key concepts A journey consists of [**tasks**](/sections/documentation/ticketing/ticket-configuration/tasks) split among multiple parties, including the **requester** (e.g. the new hire), **stakeholders** (e.g. their hiring manager), and Serval **teams** (e.g. IT and HR teams). More complex employee onboarding journeys may include additional stakeholders, such as a skip-level manager. A task could be a form submission (e.g. filling in contact info), an automated workflow (e.g. creating an Okta account for a new hire), or a manual step (e.g. verifying I-9 documentation). Tasks can be gated by time (e.g. I-9 verification is gated by the employee's start date) or dependent tasks (e.g. Okta account creation is gated on contact info). Where the stakeholder checklist is enabled, journey admins with access to inspect tasks use the arrow on a task group to open task details, including locked groups and groups assigned to other participants or **System**. Participants use the play button to continue their own available tasks; a disabled lock appears when all remaining tasks in their group are locked. In the redesigned **Others’ tasks** checklist, all assignees appear together, with their names inside each task group. Use **Filter tasks** to open the **Status** and **Assignee** submenus. You can select multiple options and combine them with search. The browser remembers your filters for this journey. **Reset filters** clears status and assignee selections while keeping your search text. If no tasks match, **Clear filters** also clears the search. Journey Overview showing the requester, manager, and team columns with their tasks ## How to get started > Enable **Journey** under **Settings → Capabilities → Ticketing**. Turning it off hides the Journeys section from the team's sidebar. ### Install a pre-built journey Serval offers Installable journeys out of the box. 1. Navigate to **Journeys** from the team sidebar 2. Click **New Journey** 3. Click **Installable Journeys** and add them to your environment ### Build a new journey We recommend using Catalyst to build new journeys that can be triggered by your team or an HRIS event. Open a chat directly from the **Catalyst** tab, describe the journey, and Catalyst drafts it for you. For more information, see [Building journeys with Catalyst](/sections/documentation/catalyst/journeys). ### Running journeys **From a trigger:** A journey can be triggered automatically by an event from an external system, such as a new-hire record appearing in Workday. For how to set up an automated trigger, see [Building journeys with Catalyst](/sections/documentation/catalyst/journeys). **From the UI:** Whether you installed a pre-built journey or built your own, they will appear in the **New Journey** dialog. Select any available journey, fill in any required inputs, and submit. When you run an existing journey workflow, a **Creating your Journey…** page shows progress and opens the new journey automatically when it's ready. If the workflow stops or takes longer than expected, you can open the original request to review its progress or select **Check again**. Checking again doesn't submit another request. **From a catalog form:** If a catalog form is configured to create a journey, submitting it creates the journey and saves your answers on its initial ticket. The form's submit workflow adds tasks under that journey. Finishing the setup workflow doesn't complete the journey while its tasks remain open. New Journey dialog listing available journey workflows, with Installable Journeys and Create new journey with Catalyst buttons ### Archive a journey To take a finished or abandoned journey off the active list, use **Archive journey** from the journey's actions or from its row actions in the list. An archived journey shows a banner and stays available to **Unarchive** later. ## Related Overview of journey tasks How admin and end users view journeys Use a journey to manage tasks for a team Onboarding and offboarding patterns for HR and People teams Design and build journeys in Catalyst # Tasks Source: https://docs.serval.com/sections/documentation/journeys/tasks The types of tasks that make up a journey, and how dependencies and task states work. **Journeys is in open beta** and the product is actively evolving. A journey consists of one or more **tasks**, which can optionally split a task into **subtasks.** Completing every subtask completes the task. Tasks and subtasks are [Serval tickets](/sections/documentation/ticketing/ticket-configuration/serval-ticket) under the hood. You can leverage all the properties of Serval tickets such as due dates, SLAs, assignment groups, visibility groups and custom fields. Each task/subtask can have an **attached workflow** that runs automatically or upon form submission. ## Manual tasks Manual tasks have no attached workflow. The assignee completes the task with **Mark complete** and can **Reopen** it if needed. An example of a manual task is I-9 document verification for a new employee. ## Form tasks Form tasks render a form for the assignee to fill in. Submitting the form runs the attached workflow with those inputs. For example, you can have a task that collects emergency contact info and runs an attached workflow to populate the info in Workday. ## Automated tasks Automated tasks run on their own with no humans involved. Some run a workflow as soon as they're ungated (e.g. Okta account creation on start date, Google account creation post Okta account creation), while others are status checks that periodically poll an external system and complete once it reports back (e.g. a background check task that polls Checkr). Automated tasks display a Serval icon. > Only admins can mark a workflow-driven task done by hand: its status normally follows the workflow. The Building journeys guide covers how tasks get their workflows and inputs (see [Creating a journey](/sections/documentation/catalyst/journeys#create-a-journey-in-catalyst)). ## Task dependencies Tasks can be gated by dependent tasks or time-based conditions. A locked task unlocks automatically when those conditions are satisfied. In personal and admin views, hover over a locked or blocking checklist task to see its dependencies. With a keyboard, focus the task and press **Down Arrow** to enter the hover card. Select a related task to reveal it in the checklist, including tasks assigned to you. In the admin overview, the destination column's filters and collapsed group are opened as needed. Select the task itself when you want to open its form. The destination checklist row stays highlighted until you click anywhere, interact with the task using the keyboard, or navigate to another task. Locked subtasks showing the dependency each one is waiting on ## Task states Each task shows its current state: | State | Meaning | | :- | :- | | **Locked** | Waiting on dependent tasks or a time-based condition (see [Task dependencies](#task-dependencies)). | | **To Do** | Ready to start and waiting on action. | | **In Progress** | Someone is actively working on it. | | **Processing** | An attached workflow is running. | | **Done** | Complete | A task can also surface an **Error** or **Warning** when a run needs attention. These roll up into the journey's **[Health Checks](/sections/documentation/journeys/monitor-and-manage#the-team-journeys-page)**. ## Related What journeys are and how the pieces fit together How admin and end users view journeys Track journeys and their tasks as an admin Use a journey to manage tasks for a team Overview of workflows Design and build journeys in Catalyst # Admin and end user views Source: https://docs.serval.com/sections/documentation/journeys/views A journey has different views so people see only what's relevant to them **Journeys is in open beta** and the product is actively evolving. ## Journey overview The overview page lists all tasks by assignee and displays their status. It is only visible to members of the Serval team that owns/created the journey. Users with access to the journey overview can also see the requester and stakeholder views. Use the view switcher above the journey to select **Journey Overview** or a participant. Wide layouts show selectable tabs. On compact layouts, or when the tabs do not fit, use the **Switch views** menu and search by name. Journey Overview listing all tasks by assignee across the requester, manager, and team columns Scroll horizontally across the task columns to reach additional assignees. In the original overview layout, you can scroll vertically over the columns to continue down the page. ### Redesign introduction During the redesigned workspace rollout, your first visit to a Journey Overview opens a short **What's new** tour. Use **Next** or the step indicators to explore the changes, the back chevron to revisit a step, and **Got it** or the close button to dismiss it. Dismissal is remembered across your journeys and devices. The tour is available for a limited time after the release. ### Team workspace Where the redesigned journey workspace is enabled, use **Switch views** above the task area to select **Journey Overview** or a participant. The journey snapshot stays on the left on wider screens, and its progress follows the selected view. On narrow screens (below 640px), or when the view tabs no longer fit the available width, **Switch views** becomes a centered dropdown. Search for a participant in the menu, or select **Journey Overview** to return to all columns. On small screens, the snapshot starts collapsed above the task area. Select **Journey snapshot** to open a bottom sheet with the full progress breakdown, links, people, and custom fields. Scroll inside the sheet to reach **Configure fields**. Your existing permissions still apply. Close the sheet, press Escape, or select outside it to return to your tasks. On wider screens, drag the edge between the snapshot and task area to resize it. Your width is remembered when you switch views or return to the journey. You can also focus the resize handle and use the arrow keys. * **Journey Overview**: A single progress ring summarizes the journey's tasks. The requester and each stakeholder with tasks have separate columns, followed by team columns. Each group shows its task count and progress. Assigned tasks show their owner's icon; unassigned tasks have no owner icon. Completed groups start collapsed. Scroll horizontally to reach additional columns. * **Participant**: The task area shows that person's task content and checklist on a plain background. The snapshot shows their progress, with a second ring for others when others have tasks. Task labels use the selected person's name. Opening a task keeps the snapshot and **Switch views** controls available. **Previous** and **Next** move between tasks inside the workspace. Select **Back to home** to return to the view you opened the task from, or select another participant using **Switch views**. For admins, pausing the pointer over a task opens its details and available management actions. Moving across tasks does not open panels. Scrolling closes an open panel and cancels pending panels; move the pointer onto a task and pause again to reopen it. Locked tasks show their prerequisites, and tasks blocking other work show their dependents. You can also focus a task and press the down arrow to enter its details, then press Escape to return to the task. Select **Journey graph** in the snapshot from either view to inspect task dependencies. Select it again to return to the overview columns. The snapshot also links to the originating workflow and journey ticket using their names. Hover over a link or focus it with the keyboard to reveal its navigation arrow. **Journey details** shows the requester and manager, with an email button when their email address is available. It also lists populated, active custom fields that your team permissions allow you to access, including information omitted from the end user view. Empty and deprecated fields aren't listed. Selecting a participant keeps this team access. Select a field row to edit its value, or use **Configure fields** below the field list to choose another field. Expand the hidden fields disclosure to reveal fields that are hidden by default. Custom-field editing is disabled for archived journeys and when you don't have permission to manage tasks. ## Requester view The requester view is for the person going through the journey (e.g. the new hire). They can see all of their tasks, as well as hover over the timeline to see tasks assigned to others. Requester view with the journey timeline and the requester's own tasks ## Stakeholder view Each stakeholder, such as the requestor's manager, gets their own view with a list of tasks assigned to them. They can also hover over the timeline to see the status of tasks assigned to others. Stakeholder view listing the tasks assigned to a stakeholder ### Progress in the checklist view Where the redesigned checklist view is enabled, requester and stakeholder pages show your unfinished tasks in a carousel above the checklist. The heading reflects your completed tasks; searching or filtering the checklist doesn't change your progress. When you view another participant, the progress heading, banner, and snapshot name that person and count only their tasks; your own view keeps the personal wording. Standalone tasks appear as individual cards without group headers in the journey home view, task checklist, and team overview. Select a task in the carousel or checklist to inspect it. Locked tasks show their prerequisites or scheduled availability; their submission actions remain unavailable. An information icon opens details for tasks that block other work. The journey snapshot shows your progress, other participants’ progress, and journey details. It collapses to leave more room for tasks on smaller screens. Select it to reopen the full breakdown. Workspace navigation is available through **Open sidebar** or the compact navigation bar on narrow screens. On task pages, the progress banner shows your personal completion count. Select it to open the suggested available task. The suggestion changes when task availability changes, not when you browse the carousel. When no task is available, the banner only shows your progress. Opening another participant’s task shows its owner and status; form instructions, fields, and reference documents are shown only for your own tasks. When you select **Submit**, the form shows submitting feedback while the request and workflow status are checked. A successful submission shows **Submitted**, followed by a transition to the next available task. Advancement checks later tasks first, then earlier available tasks. Reopening a completed task shows its submitted form. If no task is ready yet, the view waits for refreshed availability or confirmed completion. If submission fails, the form returns with your response so you can try again. You can inspect an unsigned document and leave the task without a discard warning. The warning protects edits you have made to the form and file uploads in progress. A document that still needs a signature keeps **Submit** disabled until signing is complete. A locked task also shows its prerequisites and their assignees, or its scheduled availability, in a compact warning banner beside the task icon. Select a linked prerequisite to inspect that task. The lock beside the task title still opens dependency details. On mobile task pages, **Back to home** and **Checklist** appear above the form. Select **Checklist** to open the checklist in a bottom drawer, then scroll inside the drawer to browse the full list. When AI assistance is available, **Ask Serval** appears beside **Checklist** and opens the conversation in a bottom drawer, leaving the full page height for the form. The button uses your organization’s configured assistant name and logo. In the workspace chat presentation, administrators viewing another person’s active AI conversation see a compact notice above the assistant header explaining that replying may pause AI responses. If all your remaining tasks are locked, the carousel stays visible. Open a task's dependency details to see what it is waiting for. When you finish your tasks, a completion message replaces the carousel and shows whether others still have work. If you have no assignments, the page says **No tasks assigned to you** instead. The **Others’ tasks** checklist shows all assignees together, with names and dividers inside each task group. Use the filter menu’s **Status** and **Assignee** submenus to narrow the list. You can select multiple options in either submenu and combine them with search. The browser remembers your selections for this journey. **Reset filters** clears status and assignee selections while keeping your search text. Use the available actions to continue: * **View others’ tasks**: Open the other-task checklist, clear search and filters, and expand the task groups across all assignees. * **Review completed tasks**: Open your completed tasks, or completed tasks across other assignees if you had no assignments. This clears search and assignee selections, selects the **Done** filter, and expands the relevant groups. * **Clear filters**: If no checklist tasks match your filters, clear search, status, and assignee filters while keeping your current ownership tab. ## Journey chat In the default requester and stakeholder views, you can start a chat with the Help Desk agent. Ask what a step means, how to complete it, or what is blocking you. When the agent cannot resolve something on its own, it can escalate the conversation to a ticket for your team. ### Task assistant in the redesigned view Where the redesigned task view is enabled, each task assigned to you has its own conversation when AI assistance is enabled for that task. You can ask about locked tasks while their submission actions remain unavailable. Enabling AI for the journey does not automatically enable it for every task. On wide screens, the assistant appears beside the form and checklist. The checklist moves into a drawer when the available task workspace is narrower than 1400px, preserving room for the conversation and form. At 880px or less, use the organization-branded **Ask** button beside **Checklist** to open the assistant in a drawer. The button uses your organization’s configured assistant name and logo. Use **Previous**, **Next**, or the checklist to choose a task. The assistant’s task label and conversation follow your selection. Closing and reopening the same task’s chat preserves your unsent message. The input expands for longer drafts and supports attachments. Opening chat loads the conversation; sending a message asks the assistant to respond. Tasks with AI assistance disabled do not show the assistant, even if they have earlier messages. Journey Chat panel with the Help Desk agent open beside a journey's tasks ## Related What journeys are and how the pieces fit together Overview of journey tasks Track journeys and their tasks as an admin Use a journey to manage tasks for a team The automations behind each task Design and build journeys in Catalyst # Authoring Knowledge in Serval Source: https://docs.serval.com/sections/documentation/knowledge-base/authoring Write and publish knowledge directly in Serval with a block editor, publishing workflow, and built-in agent retrieval You can author knowledge bases directly in Serval — no external wiki required. You write pages in a rich block editor, publish them when they're ready, and the help desk agent searches and cites them like any other knowledge source. Knowledge bases you author live in the **Knowledge Bases** tab of the Knowledge section, alongside the **Knowledge Sources** tab that manages synced content. Knowledge bases are in beta. When you create a knowledge document, including when acting on a knowledge suggestion, you can choose one of your Serval native knowledge bases as the destination, in addition to any connected external sources. ## Creating a knowledge base 1. In the sidebar, open **Knowledge**, then select the **Knowledge Bases** tab 2. Click **New knowledge base** and give it a name (for example, "IT Handbook") 3. Add pages and folders to build out your content Each knowledge base has a name and an icon you can customize. Your team can create as many knowledge bases as it needs — for example, one per department or per topic area. ### Pages and folders Content is organized as a tree: * **Pages** are documents you write in the block editor. Pages can nest under other pages, so a page is also a container for its children. * **Folders** are pure grouping containers for pages. Drag items in the sidebar to reorder or move them. ### Copy an external page into a knowledge base To turn read-only synced content into a page you can edit, open a page (or folder) under **From your apps** in the sidebar and choose **Copy to Serval**. Pick which authored knowledge base the editable copy should live in. Copying a folder brings everything inside it, and the original stays connected to its source, so the synced version keeps updating alongside your editable copy. Copies can only land in a knowledge base you author in Serval, not in another connected source's tree. ## Writing content Pages use a block editor with the formatting you'd expect from a modern wiki: * Paragraphs and headings (H1–H3) * Bulleted, numbered, and checklists * Quotes, code blocks, and dividers * Tables * Images — paste, drag-and-drop, resize, and caption Two inline shortcuts speed up writing: * Type **`[[`** to link to another page in the same knowledge base * Type **`@`** to mention a teammate Everything autosaves as you type — a "Saving…" indicator appears while a write is in flight. ## Drafts, publishing, and versions Pages follow a **draft → publish** model: | State | Who sees it | Agent searches it? | | :- | :- | :- | | **Draft** (never published, or edited since last publish) | Editors only | No | | **Published** | Everyone with access | Yes | * Every page starts as a draft. **Only published pages are indexed for agent retrieval** — you can iterate freely without half-finished content reaching users. * Clicking **Publish** (or **Publish changes**) snapshots the current content as a new version. The version pill in the header (for example, `v3`) shows a green dot when the live version is published and current, and an amber dot when there are unpublished changes. * **Version history** shows the timeline of published revisions — autosaves don't create versions, so history stays meaningful. * **Compare** two versions from version history to see a word-level diff of what changed between them. * **Restore** a previous version from version history: Serval brings it back as a draft, so you can review it and publish to make it live. * **Unpublish** retracts a page: the agent stops searching it and read-only viewers lose access. After you publish, an **indexing status** badge shows where the page is in the search pipeline: **Synced & searchable**, **Indexing**, or **Index failed** (with a retry option for publishers). ### Require approval to publish A team can require an approver to sign off before a published revision reaches readers. It is **off by default** — turn it on in the knowledge base settings, and nothing changes for teams that leave it alone. With it on: * **Publish** snapshots the revision and puts it in the approval queue instead of making it live. Readers keep the revision that was already published. * An approver with the **approve knowledge document** permission approves or rejects it from the queue. Approving publishes it; rejecting leaves the previous revision live. * **You cannot approve your own revision.** Someone else has to review it. * A rejected revision is final. Edit the page and publish again to start a new decision. * Turning the setting back off does not release revisions already waiting — an approver clears the queue, or the author publishes again. ### Proposals on synced articles Publishing a change set publishes the article: the accepted text becomes the version readers and the agent see, not a draft waiting for someone to press **Publish** again. If your team requires approval to publish, it waits in the approval queue instead. Because it publishes, accepting an article proposal needs permission to **publish knowledge documents** — the same permission the **Publish** button needs. Someone who can review change sets but not publish knowledge gets a clear refusal, and the article is left untouched. An article synced from a connected source can take a proposal. When you accept one, the accepted text becomes the article Serval serves, and later syncs from the source no longer overwrite it. Serval also pushes the change back to the source system where the connector supports it (Notion, Confluence, ServiceNow, Freshservice and Slab today); where it does not, the accepted text still stands in Serval. Two proposals are refused rather than applied: * The source article changed after the proposal was written. Read the article again and propose again. * The article links to other Serval pages or mentions people. A proposal is plain markdown and cannot carry those references, so edit the page in the editor instead. ## Organizing and finding content * **Search** — full-text search across pages from the sidebar * **Favorites** — star pages for yourself; favorites are personal * **Pinned** — pin pages for the whole team; everyone sees the same pinned set * **Archive** — archiving moves a page, or a whole knowledge base, to **Archive**, where it can be restored or permanently deleted Pages also support **duplicate**, **move** (to another parent or knowledge base), and **copy link** from the page actions menu. ## Access control Knowledge bases authored in Serval have two independent layers of access control: **Workspace access** controls who can view and edit pages inside Serval. **Help desk audience** controls who the agent surfaces a page to when answering requests. ### Workspace access Team roles govern who can view, create, edit, publish, archive, and delete authored knowledge content. Members with read-only access see published pages with a read-only banner — they never see drafts or version history. ### Help desk audience Each page has a **Visibility** control ("Who can find this in the help desk") that scopes which users the agent will surface the page to: * Leave it empty for **anyone in the org** * Select access profiles to restrict the audience Child pages inherit their parent's audience automatically. Restricting the help desk audience does **not** change who can view or edit the page in the workspace — the two layers are separate. To restrict a whole knowledge base, set its audience from the base's actions menu → **Visibility**, or add the base to an access profile. See [Restricting knowledge bases](/sections/access-management/configuration/access-profiles#restricting-knowledge-bases). The **Access** control on a page opens a "Who can see this page" summary that lists the audiences currently **Allowed** and **Blocked**, and explains why (which access profile allows or blocks them). Enter a specific user to check whether that person can find the page, and why. ### AI-context-only knowledge bases A knowledge base can be marked **AI context only**: its content is indexed for agent retrieval but hidden from human-facing surfaces. Use this for internal reference material the agent should know without exposing it as browsable documentation. ## Owners Every knowledge base and page you author in Serval can have **Owners**: the users or groups accountable for keeping that content correct. Ownership is separate from access, so naming an owner doesn't change who can read or edit the content. Set owners from the **Owners** action in a knowledge base's actions menu, or the **Owners** control in a page's header. Anyone who can browse the knowledge base sees the current owners; changing them requires edit access to the base. ## How the agent uses authored knowledge When a user submits a request, the help desk agent searches your published pages together with all other knowledge sources. Answers cite the page with a **View in Serval** link that deep-links straight to it. ## Learn more * [Knowledge Base overview](/sections/documentation/knowledge-base/overview) — all the ways to get knowledge into Serval * [Connect to External Sources](/sections/documentation/knowledge-base/connected-sources) — sync from your documentation apps * [Building Custom Ingestion Workflows](/sections/documentation/knowledge-base/custom-ingestion) — pull knowledge from systems without a first-party connector * [Skills vs. Knowledge](/sections/documentation/skills-vs-knowledge) — what belongs in knowledge vs. a Skill # Connect to External Sources Source: https://docs.serval.com/sections/documentation/knowledge-base/connected-sources Sync knowledge from Notion, Confluence, Google Drive, Microsoft 365, ServiceNow, Zendesk, Freshservice, GitHub, or Box If your documentation already lives in a supported app, connect it as a knowledge source. Serval syncs the content read-only, keeps it up to date automatically, and the help desk agent searches and cites it — linking users back to the original document. ## Supported sources | Source | What you can sync | | :- | :- | | **Notion** | Pages and databases | | **Confluence** | Spaces and pages | | **Google Drive** | Docs, Sheets, Slides, and uploaded PDF, Word, and Excel files | | **Microsoft 365** | SharePoint sites, libraries, and files | | **ServiceNow** | Help center articles | | **Zendesk** | Help center articles | | **Freshservice** | Knowledge articles | | **GitHub** | Documentation files in the repositories you select | | **Box** | Documents in the folders you select | Box syncs text documents (Markdown, plain text, reStructuredText, AsciiDoc) plus PDF, Word, and PowerPoint files from the folders you select — nothing is crawled until a folder is explicitly chosen. Selecting a folder makes its contents searchable by the whole team, so treat selection as a sharing decision; Box folder permissions are not yet mirrored per document. GitHub syncs documentation files, not source code. Serval reads the default branch of each repository you select and ingests text formats — `.md`, `.mdx`, `.markdown`, `.rst`, `.adoc`, `.asciidoc`, `.txt`, `.textile`, and `.org` — up to 1 MB each. It skips vendored and generated directories (`node_modules`, `vendor`, `dist`, `build`, `testdata`) and dot-directories such as `.github`. A Markdown file (`.md`, `.mdx`, `.markdown`) is named after the title it states: a `title` in front matter, or the first top-level heading. A Markdown file that states neither, and every file in the other formats, keeps its file name. To sync part of a repository rather than the whole, use **Choose GitHub paths** in the item picker. Open a repository to browse its directories, and select the directories instead of the repository itself: Serval then crawls only those paths. Scope the source before its first sync, so that nothing outside a selected path ever enters the knowledge base. Choosing paths only adds them. On a source that has already synced, the repository is usually selected already, and it stays selected. Clear it in the item picker to stop future crawls reaching outside the paths you chose. Files synced earlier stay in the knowledge base either way. Content in a system that isn't listed here? If it has an API, you can still bring it in — see [Building Custom Ingestion Workflows](/sections/documentation/knowledge-base/custom-ingestion). ## Setting up a connected source Before you can sync content, the documentation app must be installed as an integration on your team. 1. In Serval, go to **Teams** and select your team 2. Navigate to **Integrations → All integrations** 3. Find the app you want to use (for example, Confluence, Notion, or Google Drive) and click **Connect** 4. Complete the authorization flow - this typically involves signing in to the app and granting Serval access For detailed setup instructions, see the integration guide for your app: [Notion](/sections/integrations/notion), [Confluence](/sections/integrations/confluence), [Google Drive](/sections/integrations/google-workspace), [Microsoft 365](/sections/integrations/microsoft-graph), or the full [Integrations overview](/sections/integrations/overview). You only need to connect each app once per team. If a teammate has already connected the app, you can skip this step. Once the app is connected, add it to your knowledge base: 1. In the sidebar, open **Knowledge** and select the **Knowledge Sources** tab 2. Click **Manage Sources** to open the **Manage knowledge sources** dialog 3. On the **Available** tab, find the app and click **Connect** (already-connected apps appear on the **Connected** tab) 4. On the **Connected** tab, click **Choose items to sync** for the app and select the folders, spaces, or pages to include Only sync documentation you want the help desk agent to reference. Exclude drafts, internal notes, or outdated content. Before going live, verify the agent finds the right answers: 1. Open a test ticket or use the Serval chat 2. Ask questions your users would ask (for example, "What is our PTO policy?") 3. Confirm the agent returns accurate answers with links to the source document 4. Adjust synced content or filters if answers are missing or incorrect Once testing confirms accurate responses, your knowledge base is ready. The agent searches it automatically when users submit help desk requests. ## Document permissions Serval respects document permissions from the source app when the integration supports propagating access controls (Google Drive, Confluence, ServiceNow, Zendesk, and GitHub, among others). The agent only surfaces a document to a user who is allowed to see it in the source system. For GitHub, a public repository's files are readable by everyone on the team. A private or internal repository's files are readable only by the members of the GitHub teams that hold access to that repository, and by collaborators Serval can match to a Serval user. If Serval cannot resolve who may read a private repository, it hides that repository's content rather than exposing it. Serval re-reads a document's synced permissions whenever its content changes. For Google Drive, Serval also re-reads every synced file's sharing settings at least once a day, because sharing a file doesn't change its content. To apply a sharing change right away, run a manual sync from the **Knowledge Sources** tab: it re-reads the sharing settings of every synced file. If Serval can no longer read a Google Drive file's sharing settings, for example because the file was deleted or Serval's access to it was removed, it hides that file from everyone until it can read them again. ## Managing connected sources The **Knowledge Sources** tab in the sidebar gives you a centralized view of every knowledge source. From here you can: * **View all sources** - Connected apps, custom ingestion sources, and published Serval-authored content in one place * **Filter by sync status** - Find sources that are syncing, up to date, or in an error state * **Trigger manual syncs** - Run an immediate sync instead of waiting for the next scheduled run (connected sources automatically sync every four hours) * **Cancel an in-progress sync** - Stop a sync run that's currently in progress * **Pause and resume syncing** - Pause a source to stop the current run and hold all scheduled syncs until you resume it If a sync finishes but couldn't reach part of a source (often because the connected account hit a rate limit or lacks access to some of the content), that source shows a **Some content isn't searchable yet** warning. The sync still succeeded, and everything it reached is searchable. A later sync picks up the rest. When the connected service permanently refuses access to specific locations (for example, a SharePoint site or Confluence space an administrator has restricted), the source shows a **cannot be reached** warning that names those locations, such as *2 sites, 1 folder cannot be reached*. This won't clear on its own: to include that content in search, an administrator of the connected service needs to restore Serval's access. ### Toggle visibility Control whether each synced document is available to the help desk agent: | Status | Behavior | | :- | :- | | **Visible** | Agent searches this document and includes it in responses | | **Hidden** | Document is synced but not used by the agent | **How to toggle visibility:** 1. Open the **Knowledge Sources** tab in the sidebar 2. Click **Manage Sources** 3. On the integrated app, click **Choose items to sync** 4. Check the sources you want the agent to reference and uncheck the ones you want to hide This does not remove the sync connection - hidden documents stay synced but are excluded from agent responses. **When to hide documents:** * Seasonal content outside of relevant periods * Drafts under review that are not ready for users * Deprecated policies you want to keep but not cite For pages authored in Serval, use the draft/publish model instead — unpublished pages are never searched by the agent. See [Drafts, publishing, and versions](/sections/documentation/knowledge-base/authoring#drafts-publishing-and-versions). ### Review regularly Outdated information erodes trust. Review knowledge base documents: * Quarterly for general accuracy * Immediately after major policy changes * When users report incorrect answers ## Learn more * [Knowledge Base overview](/sections/documentation/knowledge-base/overview) — all the ways to get knowledge into Serval * [Building Custom Ingestion Workflows](/sections/documentation/knowledge-base/custom-ingestion) — sync from systems without a first-party connector * [Authoring Knowledge in Serval](/sections/documentation/knowledge-base/authoring) — write knowledge directly in Serval # Building Custom Ingestion Workflows Source: https://docs.serval.com/sections/documentation/knowledge-base/custom-ingestion Pull knowledge into Serval from any API or internal system using a knowledge ingestion workflow Custom knowledge ingestion brings content into your knowledge base from systems that don't have a first-party Serval connector — internal wikis, knowledge APIs, proprietary tools, or legacy systems. You point a **knowledge ingestion workflow** at the source, and Serval keeps the content synced, indexed, and searchable by the help desk agent. ## How it works A published knowledge ingestion workflow calls your system's API and returns documents as markdown — each with a display name, a stable ID, and a URL used for citations. Workflows support both full syncs and incremental (delta) syncs. On each sync, Serval chunks and embeds every document through the same pipeline as first-party connectors. Unchanged documents are skipped, and documents removed from the source are cleaned up. Serval automatically creates one read-only knowledge base per custom source, listed under **From your apps** in the Knowledge sidebar, or under **For AI only** when **AI context only** is on. Each synced document appears as a read-only page, so people can browse exactly what the agent sees. Pages link back to the original source. Once synced, the agent searches the content on every relevant request and cites the source documents in its answers. ## Setting up a custom source A workflow author builds and publishes a **knowledge ingestion workflow** — see [Knowledge ingestion workflows](/sections/documentation/workflows/Configure/types#knowledge-ingestion-workflows) for what it must return. If you don't have one yet, the setup dialog links you to Catalyst to author it. 1. In the sidebar, open **Knowledge** and select the **Knowledge Sources** tab 2. Click **Manage sources**, open the **Available** tab, and choose **Add custom knowledge source** 3. Configure the source: | Field | What it does | | :- | :- | | **Name** | Display name for the source (defaults to the workflow's name) | | **Logo** | Optional — a website domain to fetch a brand logo from | | **Workflow** | The published knowledge ingestion workflow that extracts the documents | | **AI context only** | If on, the content is used by the agent but never shown as a browsable knowledge base | Trigger a sync with **Sync now**, then ask the agent a test question that should be answered from the new content. Confirm the answer cites the right document. ## Managing a custom source Each custom source appears as a card in the Knowledge Sources tab showing its last sync time, sync-in-progress state, or any error. From the card you can: * **Sync now** — run an immediate sync instead of waiting for the schedule * **View Workflow** — jump to the ingestion workflow definition * **Settings** — edit the source configuration Source settings include these toggles: | Setting | What it controls | | :- | :- | | **Searching** | Whether the agent uses this source's content to answer help tickets | | **Cite Document Links** | Whether the agent includes links to the source documents in its answers | | **AI context only** | Whether the synced content is hidden from human-facing surfaces | Deleting a custom source permanently removes the source and all of its synced data. ## When to use custom ingestion vs. the alternatives | Situation | Use | | :- | :- | | Content lives in Notion, Confluence, Google Drive, SharePoint, ServiceNow, Zendesk, or Freshservice | [Connected source](/sections/documentation/knowledge-base/connected-sources) — no workflow needed | | Content lives in a system with an API but no Serval connector | **Custom knowledge ingestion** | | Content doesn't exist in written form yet | [Author it in Serval](/sections/documentation/knowledge-base/authoring) | ## Learn more * [Knowledge ingestion workflows](/sections/documentation/workflows/Configure/types#knowledge-ingestion-workflows) — authoring reference for the workflow itself * [Connect to External Sources](/sections/documentation/knowledge-base/connected-sources) — first-party connectors that don't need a workflow * [Custom Applications](/sections/integrations/application) — pair a custom application with your ingestion workflow # Knowledge Base Source: https://docs.serval.com/sections/documentation/knowledge-base/overview The knowledge the help desk agent searches and cites — synced from your documentation apps, ingested from any system, or authored in Serval Your knowledge base is the information the help desk agent draws on to answer requests. When a user asks a question, the agent searches every knowledge source on the team, answers from the best matches, and cites its sources with links. It's also a browsable home for your team's documentation inside Serval. Knowledge is **information** — policies, facts, and reference material. If you're telling the agent how to *behave*, that's a [Skill](/sections/documentation/skills-vs-knowledge). ## When to use knowledge base Knowledge base works best for information that already exists (or belongs) in written form: | Scenario | Why knowledge base works | | :- | :- | | **Company policies** | Agent quotes directly from official documentation | | **FAQs** | Common questions get consistent, accurate answers | | **Reference material** | Technical specs, contact lists, and lookup tables | | **Onboarding info** | Benefits, office locations, and team structures | *** ## Three ways to get knowledge into Serval Sync content from Notion, Confluence, Google Drive, Microsoft 365, ServiceNow, Zendesk, or Freshservice. Pull content from any API or internal system with a knowledge ingestion workflow. Write knowledge directly in Serval with a block editor, drafts and publishing, version history, and access controls. | Path | Best for | Content is… | | :- | :- | :- | | **[Connected source](/sections/documentation/knowledge-base/connected-sources)** | Content that already lives in a supported documentation app | Synced read-only from the app | | **[Custom ingestion workflow](/sections/documentation/knowledge-base/custom-ingestion)** | APIs, internal wikis, or systems without a first-party connector | Extracted by a workflow, synced read-only | | **[Authored in Serval](/sections/documentation/knowledge-base/authoring)** | Knowledge that doesn't live anywhere yet, or that you want to own in Serval | Written and edited in Serval | You can combine all three — multiple sources feed the same knowledge base, and the agent searches across everything. *** ## How the agent uses knowledge Whatever the path, content flows through the same pipeline: Serval chunks each document, indexes it for semantic search, and searches it on every relevant request. Answers cite their sources — synced documents link back to the original app, pages authored in Serval deep-link straight to the page. The agent retrieves knowledge in the requester's own language. When an article already exists in that language, Serval uses that version directly; when it doesn't, Serval falls back to machine translation so the requester still gets an answer. This lets multilingual teams author articles in several languages and serve each requester the closest-language version, with no configuration required. If internal sources can't answer, the agent may search the web as a last resort when **Help Desk Agent Web Search** is enabled in [Team settings](/sections/documentation/platform/team-settings#capabilities). ### Ranking rules Ranking rules are being rolled out gradually and may not be available in your account yet. Open the **Ranking** tab in the **Manage knowledge sources** dialog to nudge certain articles higher for the person asking. Two rule types are available: * **For an audience**: boost articles restricted to an audience for the people inside it. * **When properties match**: boost articles whose property equals a matching property on the reader. Each rule has a strength of **Slight**, **Normal**, or **Strong**. Ranking rules only reorder results, so a rule never hides or reveals an article that search would otherwise return. ### Permission-respecting answers The agent only surfaces content a user is allowed to see: * **Connected sources** — Serval respects document permissions from the source app when the integration supports propagating access controls; see [Document permissions](/sections/documentation/knowledge-base/connected-sources#document-permissions). * **Knowledge authored in Serval** — each page has a help-desk audience you control with access profiles; see [Access control](/sections/documentation/knowledge-base/authoring#access-control). *** ## Best practices Help the agent match documents to questions. Use "Remote Work Policy 2025" not "Policy." Use headings that match how users ask. Put key info in the first paragraph of each section. Add synonyms users might search: "PTO," "paid time off," and "vacation days" in the same doc. Focused documents perform better than 50-page handbooks. Split by policy or topic. Review quarterly and after policy changes. Outdated answers erode trust. Use workflows for automated actions, skills for troubleshooting, access requests for provisioning. # Automation Tools Source: https://docs.serval.com/sections/documentation/overview/automation-tools Four ways Serval's help desk agent resolves requests Serval's help desk agent uses four tools to handle incoming requests. Understanding when each applies helps you build an effective automation strategy. ## The Tools | Tool | What it does | Best for | | :- | :- | :- | | **Workflows** | Executes automated actions across your connected apps | Password resets, user provisioning, scheduled reports | | **Skills** | Provides step-by-step instructions the AI follows conversationally | Troubleshooting, how-to questions, decision trees | | **Knowledge Base** | Surfaces answers from your uploaded documentation | FAQs, policies, reference information | | **Access Requests** | Grants and revokes just-in-time least-privilege access automatically | Software access, application permission changes | *** ## Workflows Deterministic automations that execute the same way every time. Write once, run reliably. **Use workflows when you need to:** * Reset passwords or credentials * Add or remove users from groups * Run scheduled reports and notifications * Automate any repeatable action Create and configure workflows *** ## Skills Instructions that tell the help desk agent how to handle specific scenarios. The AI adapts its responses based on context while following your procedures. Skills can be used in combination with workflows. **Use a Skill when you need:** * Step-by-step troubleshooting flows * Answers to "how do I..." questions * Complex decision trees with multiple paths * Flexible, conversational responses A Skill can reference workflows. Create a workflow for the action, then create a Skill that tells the agent when to use it. Create and configure Skills *** ## Knowledge Base Documentation the help desk agent searches to answer questions. Upload your existing docs and the AI finds relevant answers automatically. **Use knowledge base for:** * Company policies and procedures * FAQs and common questions * Reference documentation * Information that changes infrequently Create and configure your knowledge base *** ## Access Requests A dedicated system for managing who has access to what. Handles approval routing, temporary access, and automatic deprovisioning. **Use access requests for:** * Application access grants * Permission and role changes * Time-bound access with auto-expiration * Requests requiring manager or security approval Configure access profiles and policies *** ## Choosing the Right Tool | Scenario | Recommended Tool | | :- | :- | | "Reset my password" | **Workflow** | | "How do I connect to the VPN?" | **Skill** or **Knowledge Base** | | "I need access to Salesforce" | **Access Request** | | "What's our PTO policy?" | **Knowledge Base** | | "My laptop is being slow" | **Skill & Workflow** | | "Add me to the engineering Slack channel" | **Workflow** | | "I need temporary AWS access for a project" | **Access Request** | # Day 1 Setup Source: https://docs.serval.com/sections/documentation/overview/day-1-setup Complete your initial Serval configuration in your first day This guide walks you through the essential setup tasks to get Serval operational for your organization. By the end of this guide, you'll have a fully configured help desk ready to receive and process tickets. Most organizations complete this setup in 1-2 hours. You can pause and resume at any point—your progress is automatically saved. ## Prerequisites Before you begin, ensure you have: * Admin access to your organization's Serval account * Access to your identity provider (Okta, Azure AD, or Google Workspace) * Access to your Slack workspace (if using Slack integration) * A list of team members who will be help desk agents ## Setup Flow You may follow this process out of order, depending on what prerequisites you have filled. Teams organize your help desk agents and control ticket routing. Start by creating your first team with test members. 1. Navigate to **Settings** → **Teams** 2. Click **Create Team** 3. Name your team (e.g., "IT Support", "Security", "HR") 4. Add a few test members to get started 5. Configure team-specific settings 6. [Assign roles](/sections/documentation/platform/permissions) and permissions **Recommended starting teams:** * **IT Support** — General IT requests and troubleshooting * **Security** — Security reviews, access approvals * **HR** — People operations questions Each agent can belong to multiple teams, but should have one primary team for default ticket assignment. Link your identity provider to enable single sign-on and automatic user provisioning. Go to **Settings** → **Integrations** and connect one or more of the following: * [Okta](/sections/integrations/okta) * [Google Workspace](/sections/integrations/google-workspace) * [Microsoft Graph (Azure AD)](/sections/integrations/microsoft-graph) After connecting, verify that users are syncing correctly by checking the **People** section. Set up how employees will submit requests to Serval—via Slack, Microsoft Teams, email, or web portal. [Configure Help Desk Channels →](/sections/documentation/helpdesk/channels) Start with Slack or Teams as your primary channel. You can add email and web portal later as adoption grows. Connect the applications you want Serval to interact with in workflows. Go to your team's **Integrations** page and browse the available integrations. Common applications to connect first: * **Okta** or **Azure AD** — User provisioning and access management * **Google Workspace** — Group management, calendar, and Drive * **GitHub** — Repository and team management * **Jira** — Issue tracking and project management * **Slack** — Notifications and messaging (if not already connected as a channel) * **AWS** — Cloud infrastructure management Each application you connect unlocks actions that your workflows can use. You can always add more applications later. [Browse All Integrations →](/sections/integrations/overview) If another team in your organization already has an application configured, you can **duplicate it** to your team instead of setting it up from scratch. Navigate to the application, open the **Settings** tab, and click **Duplicate** in the **Duplicate Application** section. Set up a simple automation to see Serval's AI in action. **Recommended first automation: Password Reset** 1. Navigate to **Workflows** → **Create Workflow** 2. Describe: "When someone requests a password reset, send them instructions for self-service password reset through Okta" 3. Review the generated workflow 4. Test with a sample request 5. Publish the workflow [Create Your First Workflow →](/sections/documentation/workflows/create-your-first-workflow) Explore the full range of automation capabilities available in Serval. [Learn about Serval Automations →](/sections/documentation/overview/automation-tools) Learn more about platform organization and settings [Learn about Platform Organization and Settings →](/sections/documentation/platform/platform-orientation) ## Post-Setup Verification After completing the setup, verify everything is working: 1. Open Slack and DM your help desk agent 2. Send a test message like "I need help with my laptop" 3. Verify a ticket is created in Serval 4. Check that it's routed to the correct team 1. Go to **Settings** → **People** 2. Confirm your organization's users are listed 3. Verify job titles and departments are populated 4. Check that managers are correctly assigned 1. Submit a request that should trigger your automation 2. Verify the workflow executes correctly 3. Check the ticket history for automation logs ## Common Day 1 Questions Initial sync typically completes within 5-10 minutes for organizations under 10,000 users. Subsequent syncs run automatically every hour. All progress is automatically saved. You can close your browser and return later—just sign back in to continue where you left off. Start with 2-3 IT team members who will help configure and test the platform. Expand to the full team once you're comfortable with the setup. # Welcome to Serval Source: https://docs.serval.com/sections/documentation/overview/welcome Your guide to Serval's AI-native ITSM platform Welcome to Serval! This documentation covers everything you need to deploy, configure, and operate your AI-powered help desk. New to Serval? Start with our [Day 1 Setup](/sections/documentation/overview/day-1-setup) guide to get your help desk operational in a few hours. *** ## Help Desk & Ticketing Employees submit requests through Slack, Microsoft Teams, email, or web portal. Serval's AI help desk agent handles each request intelligently: * **Routes tickets** to the right team based on request content and context * **References knowledge bases** to answer questions with accurate, sourced information * **Executes automations** to resolve common requests without human intervention * **Escalates to human agents** when needed, with full context and transparency How tickets flow through Serval—from submission to resolution Configure how employees submit requests via Slack, Teams, email, or web *** ## Automation Tools Tools to automate your help desk and reduce ticket volume. Build automations from natural language Deterministic automations for any action Shape how the AI agent responds to specific requests Connect documentation sources for AI-powered answers Just-in-time access provisioning with approval workflows *** ## Suggestions Automate the automation. Serval continuously analyzes your ticket patterns to identify repetitive requests, knowledge gaps, and opportunities for new workflows. Instead of manually building every automation, let Serval surface what matters most—then review and deploy suggestions with a single click. Learn how Serval generates and prioritizes suggestions *** ## Platform Learn your way around Serval and configure your organization. Initial configuration and team setup Navigate the interface and dashboard Roles and access control Organization-wide configuration *** ## Analytics & Insights Track help desk performance with dashboards covering request volume, AI resolution rates, time-to-resolution, and SLA compliance. Serval's AI analyzes ticket patterns to surface automation opportunities. *** ## Security & Compliance Enterprise-grade security built in: * **Encryption** — TLS 1.3 in transit, AES-256 at rest * **Access Controls** — Role-based permissions at org and team levels * **Audit Logging** — Comprehensive logs of all actions * **Compliance** — SOC 2 Type II certified * **Testing** — Regular penetration testing *** ## Deployment Options **Fully managed service** — No infrastructure to manage. Automatic updates, 99.9% uptime SLA. **Deploy in your infrastructure** — Run just the Serval worker in your network (Hybrid), or the full application single-tenant in an AWS account you own. [Self-Hosting Options →](/sections/self-hosting/index) *** ## Integrations Connect Serval to hundreds of tools including Slack, Okta, Google Workspace, GitHub, Jira, and more. See all available integrations Connect any third-party app, even if it's not in our catalog *** ## CLI & API Programmatic access to Serval resources Manage configuration from the command line Send events to external systems or trigger workflows from incoming events Manage applications programmatically *** ## Need Updates? Reach out to our team at [support@serval.com](mailto:support@serval.com) What's new in Serval # Analytics Source: https://docs.serval.com/sections/documentation/platform/analytics Track ticket resolution, AI performance, and time saved across your team Serval tracks all the data on the requests it automates for you end to end — resolution stats, time saved, money saved, time to resolve, SLA adherence, and requester feedback. Use the analytics dashboard to prove ROI, understand what's driving ticket volume, and prioritize where to invest in new automations. *** ## Accessing Analytics Open **Analytics** in the sidebar. Each team workspace has its own **Analytics**, and (for Org Admins) the **Organization** workspace has an org-level **Analytics** entry. Choose a team using the main app workspace switcher before opening Analytics. The landing page is scoped to a single team and displays lifetime statistics alongside time-series charts for ticket trends, resolution times, SLA performance, and feedback. When the team has SLA policies configured, an **SLA compliance** summary card headlines your overall met, breached, and at-risk rate, with a link to the detailed SLA view. Where the Analytics workspace is enabled, Analytics opens **Overview**, with a dedicated sidebar containing **Overview**, **All dashboards**, and your custom sections. From an individual dashboard, select **Analytics** in the breadcrumb to return to Overview. Select **Back to app** to return to the main workspace. The Analytics sidebar stays scoped to the current team. In the earlier layout, select **Dashboards** in the Analytics header to find your [custom dashboards](#custom-dashboards). Use **Collapse sidebar** beside **Back to app** to hide navigation. Select **Open sidebar** in the page header to reopen it. On narrow screens, **Open navigation** in the bottom bar opens the Analytics sidebar. Widgets stack vertically to fit the available width. This leaves the saved desktop layout unchanged; use a wider screen to move or resize individual widgets. ### Organize your Analytics workspace **Overview** starts with built-in team dashboards. Select **Create dashboard** to [build a new dashboard](#build-a-custom-dashboard). To include another dashboard, open its actions menu in **All dashboards** and select **Add to Overview**. On Overview, drag a dashboard by its handle, or use **Move up** and **Move down** from its options menu. **Remove from Overview** removes the dashboard from your Overview without deleting it. **All dashboards** includes your team's built-in and custom dashboards. Search by name, switch between **Grid view** and **List view**, and open a dashboard to explore its widgets. Grid cards show a preview above the dashboard's name and metadata. Use **Built-in** and **Databases** to filter the gallery. Select both to show either kind, or clear both to show every dashboard. Select a chip's **×** to remove that filter. Search narrows the selected kinds by name: on desktop, the search icon expands a field beside the view selector; on smaller screens, the search field stays visible below the controls. In All dashboards, grid cards identify database dashboards with a **Database** badge. Open one to see its source database's name, icon, and color above the dashboard title. Select that chip to open the database in your current team, including databases shared with your team. If the source cannot be accessed, the chip shows **Database unavailable** without a link. Use custom sections to organize dashboard shortcuts. Sections start expanded and remember when you collapse them: 1. Select **New section** directly below **All dashboards** in the sidebar, enter a **Section name**, and select **Create**. 2. Open a dashboard's actions menu, select **Move to section**, and choose the section. 3. Select a section name to expand or collapse its dashboard shortcuts. Use its **Section actions** menu to **View section**, rename, move, or delete it. Moving a dashboard into a section leaves it available in **All dashboards**. A dashboard can also appear on Overview. Deleting a section keeps its dashboards. Overview order, sections, and gallery display mode are personal to you. Dashboard content keeps its existing team permissions. Select a dashboard title to open it; edits change the underlying dashboard, not just your Overview. Custom dashboards are in beta. *** ## Lifetime Statistics The lifetime statistics section shows cumulative metrics for the selected team: Total tickets resolved by Serval AI without human intervention Total number of workflow executions across all tickets Estimated time saved based on workflow runs and AI resolutions Estimated cost savings based on time saved and labor rate Time saved is calculated as 10 minutes per AI-resolved ticket and 5 minutes per workflow run. Money saved uses a default labor rate of \$100/hour, which you can configure. *** ## Tickets Chart The tickets chart shows how tickets are distributed across resolution categories over time as a stacked bar chart, with a total ticket count and percentage for each category. ### Ticket Categories Serval resolved the ticket without human intervention Serval ran workflows, but a human ultimately resolved the ticket Serval escalated to a human without running any workflows Resolved without Serval involvement (includes Silent mode tickets and imported tickets) The chart also includes **Canceled** and **Open** categories, which are hidden by default. Click category labels in the legend to toggle their visibility. ### Using the Tickets Chart * **Toggle categories**: Click category labels to show or hide them in the chart * **Filter tickets**: Apply filters to analyze specific subsets (by ticket type, priority, label, assignee, etc.) * **Time range**: Select a preset interval (1W, 1M, 3M, All) or choose a custom date range * **Granularity**: Switch between daily, weekly, monthly, or quarterly views * **Export data**: Download ticket data as CSV Use the tickets chart to identify which categories generate the most volume and where to invest in automation or workflow improvements. *** ## Time to Resolve The time to resolve (TTR) chart shows how long it takes to resolve tickets, displayed as percentiles and mean over time. ### TTR Metrics The chart displays: * **95th percentile (p95)**: 95% of tickets resolve faster than this * **75th percentile (p75)**: 75% of tickets resolve faster than this * **Median (p50)**: Half of tickets resolve faster than this * **25th percentile (p25)**: 25% of tickets resolve faster than this * **Mean**: Average resolution time ### TTR by Assignee Below the main chart, a breakdown by assignee shows: * Total tickets resolved per assignee * Mean and median TTR per assignee * Number of SLA breaches per assignee TTR is calculated from ticket creation to completion. Only completed tickets are included. ### Using the TTR Chart * **Filter by assignee**: Apply filters to analyze specific team members or ticket types * **Export data**: Download TTR data as CSV * **Time range and granularity**: Adjust the time window and granularity to match your analysis needs *** ## SLA Performance The SLA performance chart tracks how well your team meets SLA deadlines. Dashboard SLA widgets support **All time** as well as shorter windows; statistics and completion-time percentiles use the full selected history. ### SLA Metrics * **SLA met**: Tickets completed before their SLA deadline * **SLA breached**: Tickets that exceeded their SLA deadline The chart displays: * A pie chart showing the overall SLA compliance rate * A time-series bar chart showing SLA performance over time Only tickets with configured SLA policies are included in this chart. Configure SLA rules to start tracking SLA performance. ### Using the SLA Chart * **Filter tickets**: Analyze SLA performance for specific ticket types, priorities, or assignees * **Time range**: View SLA trends over different time periods * **Identify patterns**: Look for periods with higher breach rates to understand capacity issues *** ## Feedback The feedback chart shows requester satisfaction with Serval's responses. In the Analytics workspace, Feedback is included on your initial Overview when feedback collection is enabled for your team. You can also find it in All dashboards. ### Feedback Metrics * **Positive**: Requester indicated satisfaction with the response * **Negative**: Requester indicated dissatisfaction with the response The chart displays: * A pie chart showing the overall positive feedback percentage * A time-series bar chart showing feedback trends over time Use the tabs at the top of the chart to filter by feedback target: * **All**: All feedback across AI and human responses * **Serval**: Feedback on Serval AI responses only * **Agent**: Feedback on human agent responses only Enable feedback collection to gather requester responses. Only tickets with feedback responses are included in these metrics; the dashboard can be empty before responses are collected. ### Using the Feedback Chart * **Track satisfaction trends**: Monitor how feedback changes over time * **Filter by ticket type**: Identify which categories receive better or worse feedback * **Improve AI performance**: Use negative feedback patterns to identify areas where Skills or workflows need improvement *** ## Time Range and Granularity All charts support flexible time range selection. ### Preset Intervals * **1W**: Last week * **1M**: Last month * **3M**: Last 3 months * **All**: All available data You can also select a custom date range for precise analysis periods. ### Granularity * **Daily**: View day-by-day trends * **Weekly**: View week-by-week patterns * **Monthly**: View month-by-month trends * **Quarterly**: View quarter-by-quarter trends The system automatically selects an appropriate granularity based on your time range, but you can override it manually. *** ## Filtering All charts support filtering to analyze specific subsets of tickets: * **Ticket Type**: Filter by request, task, or incident * **Category**: Filter by ticket category * **Priority**: Filter by ticket priority * **Status / Status Group**: Filter by ticket status * **Assigned To**: Filter by assigned user * **Requested By**: Filter by the requester * **Labels**: Filter by ticket labels * **Date Created / Date Completed**: Filter by ticket dates * **SLA**: Filter by SLA status * **Feedback**: Filter by feedback sentiment Some filters are excluded from specific charts where they would be redundant — for example, the SLA filter is excluded from the SLA chart, and the feedback filter is excluded from the feedback chart. The **Category** filter is offered on a single team's charts only. It isn't available on the organization-level (all-teams) view, since categories are defined per team. *** ## Exporting Data Export analytics data for further analysis: * **Tickets CSV**: Download ticket data from the tickets chart * **TTR CSV**: Download time-to-resolve data from the TTR chart Exported CSVs include ticket details and can be imported into spreadsheet applications or business intelligence tools. *** ## Custom dashboards Custom dashboards are in beta. Creating and editing dashboards requires analytics edit access for the team. With view-only access, you can open and explore dashboards but not change them. Beyond the built-in charts, you can build your own custom dashboards. A custom dashboard is a grid of widgets, and each widget runs a workflow that queries your data. One dashboard can combine Serval data (tickets, access requests, assets, and workflow runs), data from connected apps such as ServiceNow or GitHub, and public APIs. Each custom dashboard belongs to a single team. Find dashboards in **All dashboards** where the Analytics workspace is enabled, or through **Dashboards** in the Analytics header in the earlier layout. The dashboard actions menu also lets you pin a dashboard to the main app sidebar. ### Viewing and editing Use the mode selector at the top right of a dashboard to switch between **Viewing** and **Editing**. Viewing lets you explore the data. Editing enables widget configuration, rearranging, and resizing. Widgets keep their normal size in Editing, with dotted outlines and no card shadows. Hover over or focus a widget to reveal its corner resize handles and top move grip. Pencil and delete controls remain available. Editing requires analytics edit access for the team. In Editing, the dashboard name and description appear in separate rounded text boxes and save automatically after you pause typing or leave either field. You can keep typing while a save is in progress. When you leave a changed field, a **Changes saved** toast confirms the save succeeded. If a save fails, your text stays in place and you can select **Retry**. After you change the default time range, select **Save as default** beside the time picker to save it. Widget configuration saves from its own panel. Adding, removing, moving, and resizing widgets save as you make those changes. To delete a dashboard, switch to **Viewing**, open the dashboard actions menu beside the mode selector, and select **Delete**. Confirm **Delete** to remove the dashboard and its widgets. This requires analytics edit access. ### Configuring a widget Select a widget's pencil button in **Editing** to open its preview and configuration panel. Edit the title at the top. For workflow-backed widgets, choose the workflow in **Source Workflow**, select **Run Workflow** to refresh the preview, or use **View Workflow** to open its definition. **Advanced** contains workflow inputs, raw arguments, and the output schema. **Visualization** combines widget and chart types with their supported settings; boolean settings use **Yes** and **No** choices. Changes appear in the preview; select **Save** to apply them or **Cancel** to discard them. When the workflow supports the time-range control, choose **Dashboard** to follow the dashboard range, **Relative** for a rolling preset, or **Specific** for fixed dates. In Specific, use the **From** and **To** date pickers, then select **Apply**. Canceling or dismissing the date selection leaves the widget's range unchanged. Drag the empty canvas to move the preview, or use **Hand tool** to drag over the widget. Scroll or pinch to zoom. The bottom-left controls let you zoom out or in, select the percentage to return to 100%, and use **Fit to view** to center the widget within the available space. Panning and zooming don't change the widget's size or position on the dashboard. ### Widget types A dashboard can mix any of these widgets: * **Charts**: bar, line, area, and pie charts * **Tables**: row-level views, top-N lists, and detail grids * **Stats**: single-number KPIs (counts, averages, sums) with an optional comparison below the value and a compact trend chart beside it * **Text**: section headers and inline commentary * **iFrame**: embeds of external content (only sites that support embedding) * **JSON**: raw structured output, useful for debugging Charts that split a measure into multiple series (a bar, line, or area chart grouped by a field, or a pie chart with a category) can show a breakdown. Turn on **Show breakdown by group** in the widget editor, and a panel beside the chart shows a grand total and each series' individual count. Hiding or showing a series in the legend recomputes that grand total against the visible series. The per-series counts stay at their full values. Every dashboard has a time-range control. Serval passes the active range to every widget, but a widget responds only if the workflow behind it uses that range. You can also pin a widget to its own fixed window so it ignores the dashboard control. ### Chart colors Charts automatically use a seventeen-color brand palette beginning with purple when neither the workflow nor the widget supplies a color choice. When editing a chart widget, open **Series colors**. Use **Brand palette** for ordinary categories, such as teams or products. **Neutrals** offers gray shades, and **Semantic** colors express positive, warning, negative, or neutral outcomes. Choose meanings in the context of the chart. Use neutral for canceled or retired states unless the chart's purpose makes them a positive or negative outcome. **Default** shows the effective color, including colors supplied by the workflow. A series override applies to that widget and takes precedence over the workflow's choice. **Reset to default** removes the override and restores the workflow color or automatic palette color. Custom choices remain supported and are preserved when you edit unrelated settings. Hiding a series in the legend doesn't reassign the remaining colors. Charts with more than seventeen automatic series repeat the palette. Pie charts display positive values only. ### Stat comparisons and health When a stat has a trend comparison, use **Meaning** to choose how to interpret movement: | Meaning | Use when | | - | - | | **Higher is better** | An increase is beneficial, such as higher availability. | | **Lower is better** | A decrease is beneficial, such as lower response time. | | **No good/bad meaning** | Movement has no preferred direction, such as request volume without a growth or reduction goal. | The comparison badge and trend chart use this meaning. The percentage and arrow still show the actual change; changing **Meaning** doesn't reverse the numbers or change category colors. Thresholds describe current health separately and color the value or background. For example, availability can remain above its healthy target while its comparison shows that it is worsening. Without a comparison, the trend chart uses an active threshold color or the default purple. ### Click-through dashboards A **report** is the list of tickets behind a ticket-backed widget. The widget's workflow creates it on each run, and it holds each ticket's reference plus the fields the widget is broken down by. Widgets with a report show a **View report** action, which opens the report in a side panel. Each row is a ticket shown by its reference (for example `IT-42`). Click a row to open the ticket in a new tab, and use the column header filters to narrow the page you're viewing. If a ticket-backed widget doesn't show **View report**, ask Catalyst to add reports to your widgets or dashboard, then use **Refresh** on the dashboard. To see only the tickets behind one part of a widget, select that part directly: a bar, a segment of a stacked bar, or a slice of a pie chart, or a row in a table widget. The side panel opens with the report filtered to your selection, and the selected mark stays highlighted while the rest of the chart dims. In a chart grouped by a field, the filter matches both the category and the series you selected. In a chart that stacks several measures, selecting a segment shows the tickets for the whole bar. ### Build a custom dashboard You can build a dashboard using Catalyst or manually: * **Using Catalyst (recommended)**: Describe the dashboard in plain language. Catalyst designs the widgets, writes the workflows behind them, and stages a draft for you to review and publish. You can also ask Catalyst to iterate on an existing dashboard (for example, add or remove widgets, rename it, change the time range, or swap the data behind a widget). For more information, see the Catalyst guide to [Building dashboards](/sections/documentation/catalyst/dashboards). * **Manually**: Create a blank dashboard, then select **Add Widget**. The new widget opens immediately in the configuration sidebar so you can choose its type and content. Select **Save** to close the sidebar and reveal the widget at the bottom of the dashboard in **Editing** mode, ready to move or resize. Design widgets, wire up the workflows behind them, and iterate on a dashboard from natural language *** ## Best Practices Filter by "Unassisted" tickets to see which request types Serval escalates most often — those are your best candidates for new workflows Monitor the ratio of AI-resolved to total tickets over time. A rising rate means your workflows and Skills are working. Negative feedback patterns point to areas where Skills or workflows need refinement Download ticket CSVs to share resolution stats and time savings with leadership *** ## Common Questions Serval estimates 10 minutes saved per AI-resolved ticket and 5 minutes saved per workflow run. These estimates are based on typical time required for human agents to handle similar tasks. **AI resolved** means Serval completed the ticket entirely without human intervention. **AI assisted** means Serval ran workflows on the ticket, but a human agent ultimately resolved it. Charts require relevant data to display: * **TTR chart**: Needs completed tickets in the selected time range * **SLA chart**: Needs tickets with configured SLA policies * **Feedback chart**: Needs feedback collection enabled and tickets with feedback responses Try adjusting your time range or filters, or ensure the relevant features are configured. * Create workflows for common request types * Add Skills for frequently asked questions * Review escalated tickets to identify automation opportunities * Use the tickets chart to see which categories have low AI resolution rates This category includes tickets resolved without Serval's involvement. This can happen when: * Tickets are in Silent mode * Tickets are imported from external systems already resolved * Tickets are manually marked as resolved without Serval processing them Use the team switcher in the analytics header to view a different team's data. Analytics is scoped to one team at a time. # Data redaction Source: https://docs.serval.com/sections/documentation/platform/data-redaction Add organization-specific credential patterns to help desk message scrubbing Organization Admins can add regular expressions for internal credential formats under **Organization Settings → Security → Data redaction**. These rules extend Serval's built-in secret detection for help desk messages across your organization's teams. Custom redaction is available to enrolled organizations. If the section is missing, contact Serval support to request access. ## Add and test a rule 1. Open [Security settings](https://app.serval.com/admin/settings/security#data-redaction) and select **Add pattern**. 2. Enter a descriptive name and a regular expression for your credential format. For example, `ACME_SECRET_[A-Za-z0-9]{24}` matches a distinctive prefix followed by 24 letters or digits. 3. Enter synthetic sample text containing matching and non-matching examples, then run the preview. The preview applies Serval's built-in rules and your candidate rule using the same engine as message scrubbing. Sample text is not saved with the rule. 4. Select **Save disabled** to keep the rule for later, or **Save and enable** to start applying it after a successful preview. Editing a rule does not change its saved behavior until you save. If the rule is enabled, its previous expression remains active while you edit. Test realistic examples before saving: redacted values cannot be recovered from the stored message. ## Supported expressions Expressions use Go's RE2 syntax. Lookarounds and backreferences are not supported. Each expression can contain at most 200 characters, and an organization can have up to 50 rules. Use a distinctive credential prefix and a constrained body. Expressions that match empty text or common examples of ordinary text, emails, phone numbers, or UUIDs are rejected. This feature is intended for credential formats; it is not a general personal-data classification system. ## Scope and timing Enabled rules replace matching text with `[REDACTED]` in newly written or updated help desk messages and supported stored external-message payloads. Rules apply across teams in the organization. Changes normally propagate within two minutes. | Surface | Text covered when Serval saves or updates it | | - | - | | Web, API, worker, and imported help desk messages | Message bodies, including subsequent edits and synced updates. | | Slack, Microsoft Teams, email, WhatsApp, and phone | Ingested help desk message text, phone transcripts, and saved interrupted replies. | | Help agents and ticket operations | Saved AI replies, escalation and internal notes, workflow email notes, and delivery-failure diagnostics stored as notes. | | Personal helpdesk conversations | Saved conversation text and messages relayed or delegated to team tickets. | | Stored external message and ticket mirrors | JSON string values in supported channel payloads. Custom rules do not change JSON keys or numeric values. | These rules cover saved message text and the listed mirrors. They do not provide a guarantee for every ticket field, such as ticket names, summaries, other metadata, or separate tool arguments and results. The rules do not scan historical data, attachment contents, or Catalyst workspaces. They do not remove a message already stored by an external service, such as Slack or Microsoft Teams. Do not treat the preview as a scan of existing data or a guarantee that every live stream, external delivery, or model input is filtered by your custom rule. If the policy cannot be refreshed temporarily, Serval continues using the last successfully loaded policy. A message operation that cannot load any trusted policy fails so it can be retried. ## Manage rules Organization Admins can edit, disable, or delete rules. Disabling or deleting a rule affects future message writes; it cannot restore text already redacted. Changes are recorded in the organization's audit log. Serval's built-in detectors remain active independently of custom rules. They recognize known credential formats, including Serval API-key secrets. You do not need to add a custom expression for those formats. # Data residency Source: https://docs.serval.com/sections/documentation/platform/data-residency Choose where your organization’s data will be stored and processed Serval customers have the ability to choose their data center region when creating their organization. ## Supported data center locations Serval operates two data center regions. Customer data is both stored and processed within the region your organization is assigned to. | Region | AWS location | Application URL | Public API base URL | | :- | :- | :- | :- | | United States | US West | `https://app.serval.com` | `https://public.api.serval.com` | | European Union | EU Central | `https://app.eu1.serval.com` | `https://public.eu1.serval.com` | If your business requires operations in both regions, you can run a separate Serval organization in each. API requests must be sent to the base URL for the region where your organization is hosted. EU organizations use `https://public.eu1.serval.com`; requests to the US base URL will not reach EU-region data. The region is **set at organization creation** and cannot be changed afterward. Migrating to a different region requires creating a new organization; users, tickets, audit logs, and integration connections are not preserved. ## What customer data is stored and processed in your region The following categories of data live entirely within your assigned region. None of it leaves your region under normal operation. * Ticket content and message bodies * Knowledge base articles, embeddings, and vector indexes * Customer files and uploaded attachments * User profile data — names, email addresses, profile photos * Workflow definitions and execution history * Authentication tokens and session state * Application audit logs ## SSO and SCIM are handled by WorkOS Serval uses [WorkOS](https://workos.com/) as a subprocessor for SAML SSO and SCIM directory sync. This processing is not confined to your organization's selected Serval region—WorkOS operates its own global infrastructure independent of the US/EU split described above. Identity data that flows through these features (IdP profile attributes, group memberships) is processed by WorkOS regardless of whether your organization is on `app.serval.com` or `app.eu1.serval.com`. ## Operational independence between regions The US and EU regions run in independent AWS accounts with independent IAM, KMS keys, networking, and deploy pipelines. Databases are not replicated between regions. Services in one region never call services in another region for any customer-data operation. ## Frequently asked questions No. Customer data is stored and processed in your selected region and is not replicated outside it. No. The region is set at organization creation and cannot be changed afterward. If you operate in both regions, you can run a separate organization in each. The current list is maintained at [trust.serval.com](http://trust.serval.com) No. WorkOS operates independently of the US/EU regions described above, so identity data handled through SAML SSO and SCIM directory sync is processed by WorkOS's own infrastructure rather than pinned to your organization's region. # Set up Microsoft Entra ID SSO with Serval (SAML) Source: https://docs.serval.com/sections/documentation/platform/entra-saml-setup Configure SAML 2.0 single sign-on between Microsoft Entra ID and Serval, including prerequisites, supported features, enterprise-app setup, and the SAML attributes Serval expects. This guide walks a Microsoft Entra ID administrator through connecting Entra ID (formerly Azure AD) to Serval for SAML 2.0 single sign-on, so your users sign in to Serval with their Entra credentials. Serval brokers SAML through [WorkOS](https://workos.com/); the in-product setup gives you the exact values to paste into Entra. ## Prerequisites Before you begin, make sure you have: * **A Serval administrator account**: an account with the **Admin** organization role in the Serval organization you're configuring. Sign-in URL: `https://app.serval.com`. * **Entra administrative permissions**: a role that can create enterprise applications, configure SAML single sign-on, and assign users (for example **Cloud Application Administrator** or **Application Administrator**). * **A verified domain in Serval**: verify the email domain your users sign in with under **Organization → Security** in Serval before you enable SSO. SAML sign-in is rejected for users whose email domain isn't verified on your organization. ## Supported features | Feature | Supported | | - | - | | SP-initiated SSO | Yes | | IdP-initiated SSO | Yes | | Just-In-Time (JIT) provisioning | No | | User provisioning (SCIM) | Yes, via [SCIM directory sync](/sections/documentation/platform/org-settings#security-sso-scim-and-domains) | | Single Logout (SLO) | No | | Force authentication | Yes | Serval doesn't create accounts through SAML JIT provisioning. To provision and deprovision users automatically, configure **SCIM** alongside SSO from **Organization → Security**. ## Add a Serval enterprise application in Entra Serval isn't listed in the Entra application gallery. Create a non-gallery enterprise application, then configure SAML on that app. 1. In the [Entra admin center](https://entra.microsoft.com), go to **Identity → Applications → Enterprise applications**. 2. Select **New application**. 3. Select **Create your own application**. 4. Enter a name (for example, `Serval`). 5. Select **Integrate any other application you don't find in the gallery (Non-gallery)**. 6. Select **Create**. ## Configure SAML SSO Serval generates a unique Service Provider (SP) configuration for your organization. Retrieve those values from Serval, then enter them in the **enterprise application you created** above. When you select **Configure SSO** in Serval, the guided setup shows generic "create a new SAML app" instructions. For Entra, skip creating a second app; you only need to copy your **ACS URL**, **Entity ID**, and **IdP metadata** from that screen into the non-gallery application you already created. In Serval, switch to the **Organization** workspace, open **Settings → Security**, and select **Configure SSO**. This launches a guided setup that displays your organization's **Reply URL (ACS URL)** and **Identifier (SP Entity ID)**. In the Serval enterprise application, open **Single sign-on**, select **SAML**, then edit **Basic SAML Configuration**: * **Identifier (Entity ID)**: the SP Entity ID from Serval. * **Reply URL (Assertion Consumer Service URL)**: the ACS URL from Serval. Leave **Sign on URL** blank unless the guided setup asks you to set one. Save your changes. On the same **Single sign-on** page, under **SAML Signing Certificate**, copy the **App Federation Metadata URL**. Provide it in the Serval guided setup so Serval can trust assertions signed by your Entra tenant. Assign the Serval app to the users or groups who should have access (**Users and groups**). Then sign in from the Entra **My Apps** portal (IdP-initiated) or from Serval's sign-in page (SP-initiated) to confirm access. ## SAML attribute statements Confirm these mappings under **Attributes & Claims** in the Entra app's SAML settings. Entra's default claims already use XML URIs. Leave those defaults. The guided setup maps them. Don't add extra claims named `id`, `email`, `firstName`, or `lastName`. | Source | Default claim | | - | - | | `user.mail` | `emailaddress` | | `user.givenname` | `givenname` | | `user.surname` | `surname` | | `user.userprincipalname` | `name` | Email identifies the user. WorkOS takes a stable identifier from NameID, so you don't need a separate `id` claim. Sign-in fails if email is missing. Entra only populates `user.mail` when the user's **mail** attribute is set. For accounts without a mailbox, set **Entra → Users → the user → Contact information → Email**, or map the email claim to `user.userprincipalname` if that value is an address on your verified domain. ## SP-initiated sign-in Users can start sign-in from Serval directly: 1. Go to `https://app.serval.com`. 2. Enter your work email. Serval detects your organization's SSO domain and redirects you to Entra. 3. Complete authentication in Entra. Serval returns you to the app, signed in. This SAML enterprise application isn't the **Continue with Microsoft** button on the login card, the [Microsoft Graph](/sections/integrations/microsoft-graph) integration, or the [employee portal widget](/sections/documentation/helpdesk/embedded-widget/entra-oidc). ## Troubleshooting * **`Profile domain does not belong to the target Organization`**: the signed-in user's email domain isn't verified on your Serval organization. Verify the domain under **Organization → Security**. * **"Invalid SAML Response"**: the Entra metadata registered in Serval doesn't match the app sending the assertion (for example, after recreating the enterprise application). Re-send the current **App Federation Metadata URL** to Serval. * **User not assigned**: Entra denies sign-in for anyone who isn't assigned to the enterprise application. Open **Users and groups** and assign the user or a group they belong to. * **Locked out after enabling Require SSO**: enabling **Require SSO** makes SSO the only sign-in method for members on a verified domain. If Entra sign-in is unavailable, an administrator can restore access through magic-link sign-in for guest accounts, or contact your Serval representative. Turning on **Require SSO** disables password and magic-link sign-in for members on your verified domains. Confirm SSO works end to end for at least one administrator before enforcing it. If sign-in still fails after these checks, reach out to your Serval representative or Serval support with the time of the attempt and the error message shown. # Inbox Source: https://docs.serval.com/sections/documentation/platform/inbox A dedicated place in the Serval web app for notifications, filters, and bulk read actions The **Inbox** is Serval’s in-product notification center. It pulls together updates you care about—approvals, tickets, access, and other events—so you are not hunting through Slack alone to find what needs attention. ## Open the Inbox In the Serval web app, choose **Inbox** in the main sidebar (near **New request** and **Tickets**). You will also see an **unread indicator** when there is new activity. The page opens at `/inbox` with a **list of notifications** on the left and a **detail panel** on the right when you select an item. ### Open a denied change review Select a **Review denied** notification to inspect the review, its status, and resource changes directly in the detail panel. The notification list stays visible while you review the changes. Promotions open in the source team's context. If the detail panel shows **Couldn't load the review**, choose **Retry** to load it again. If your current team access cannot resolve the review, the panel shows **Review unavailable with your current access**. The recorded outcome remains visible. ## Filter and focus Use the **filter** control to narrow the list: * **Notification type**: Show only certain kinds of events (for example access, tickets, or approvals, depending on what your organization receives). * **Team**: Focus on notifications tied to a specific team. * **Sent by**: Filter to activity from a particular person. * **Approval status**: Narrow approval notifications to a state such as Awaiting response, Approved, or Denied. Use **Awaiting response** to surface approvals you still need to act on, including ones you've already opened that an **Unread only** view would otherwise hide. Turn on **Unread only** when you want a tight queue of what you have not opened yet. ## Views The inbox title includes a **view menu**. Switch between: * **All Notifications**: every notification. * **Pending Approvals**: only approval requests still awaiting your decision. Pin the **Pending Approvals** view to add a sidebar shortcut that opens straight to it. A view composes with the filters above, so an active filter (such as **Sent by**) still narrows what the view shows. ### Clear the approval queue In the **Pending Approvals** view, **Approve all** approves every pending request in the current view behind one confirmation. Requests that require a justification are skipped so you can handle them individually. You can also work the queue from the keyboard: **j** and **k** move the selection, and **y** and **n** approve or deny the selected request. A decision that needs a justification is left to the row's buttons. ## Mark all as read When you have cleared what you needed, open the header **menu** (⋮) and choose **Mark all as read** to reset unread state for the current team context in one action. ## Who it is for Inbox is especially useful if you **own approvals**, **cover multiple teams**, or get a **high volume** of Serval notifications and need a single surface to triage, filter, and catch up. # Set up Okta SSO with Serval (SAML) Source: https://docs.serval.com/sections/documentation/platform/okta-saml-setup Configure SAML 2.0 single sign-on between Okta and Serval, including prerequisites, supported features, catalog setup, and the SAML attributes Serval expects. This guide walks an Okta administrator through connecting Okta to Serval for SAML 2.0 single sign-on, so your users sign in to Serval with their Okta credentials. ## How setup works Setup is a round trip between Serval and Okta. Serval brokers SAML through [WorkOS](https://workos.com/), and the in-product **Configure SSO** flow gives you the values you need and collects the one value Okta produces: 1. In **Serval**, start **Configure SSO** to get your **connection ID** (and the SP endpoints derived from it). 2. In **Okta**, add Serval from the catalog and enter that connection ID. 3. Back in **Serval**, paste your **Okta metadata** so Serval trusts your identity provider. Keep the Serval **Configure SSO** screen open in one tab and the Okta Admin Console in another — you'll move between them. ## Prerequisites * **A Serval administrator account**: an account with the **Admin** organization role in the Serval organization you're configuring. Sign-in URL: `https://app.serval.com`. * **Okta administrative permissions**: a **Super Administrator** (or an admin role that can add and configure OIN applications) in your Okta org. * **A verified domain in Serval**: verify the email domain your users sign in with under **Organization → Security** in Serval. SAML sign-in is rejected for users whose email domain isn't verified on your organization. ## Supported features | Feature | Supported | | - | - | | SP-initiated SSO | Yes | | IdP-initiated SSO | Yes | | Just-In-Time (JIT) provisioning | No | | User provisioning (SCIM) | Yes, via [SCIM directory sync](/sections/documentation/platform/org-settings#security-sso-scim-and-domains) | | Single Logout (SLO) | No | | Force authentication | Yes | Serval doesn't create accounts through SAML JIT provisioning. To provision and deprovision users automatically, configure **SCIM** alongside SSO from **Organization → Security**. ## Set up SSO In Serval, switch to the **Organization** workspace, open **Settings → Security**, and select **Configure SSO**. Copy your **connection ID** — a short identifier like `conn_01ABC…`. It's shown as your **Audience URI (SP Entity ID)** and as the last segment of your **ACS URL** (`https://auth.workos.com/sso/saml/acs/`). Leave this screen open. You'll return to it in the last step to hand Okta's metadata back to Serval. In the Okta Admin Console, go to **Applications → Applications → Browse App Catalog**, search for **Serval**, and select **+ Add Integration**. On the **General Settings** page, set the **Application label** (for example, `Serval`) and paste your **Serval SSO Connection ID** from the previous step into the connection ID field. Okta uses it to build your ACS URL and Audience URI automatically, so you don't enter any URLs by hand. Select **Done**. Add Serval from the catalog — **don't create a custom SAML app**. The catalog app builds the SAML endpoints from your connection ID; you only supply the connection ID and, later, your Okta metadata. Open the Serval app's **Sign On** tab and confirm the populated settings: * **Single sign-on URL (ACS URL)**: `https://auth.workos.com/sso/saml/acs/` * **Audience URI (SP Entity ID)**: `` * **Name ID format**: `EmailAddress` * **Application username**: `Email` Then add the four [attribute statements](#saml-attribute-statements) below. All four are required. This is what lets Serval trust logins from your Okta org — **SSO fails until you complete it.** On the Serval app's **Sign On** tab in Okta, copy the **Metadata URL** (or download the IdP metadata / certificate). Return to the Serval **Configure SSO** screen from step 1 and provide it where prompted. On the app's **Assignments** tab, assign Serval to the users or groups who should have access. Then confirm sign-in works both ways: from the Okta dashboard (IdP-initiated) and from Serval's sign-in page (SP-initiated). ## SAML attribute statements Serval requires all four attributes below. Add them under **Attribute Statements** in the Okta app's SAML settings. | Attribute name | Value | | - | - | | `id` | `user.id` | | `email` | `user.email` | | `firstName` | `user.firstName` | | `lastName` | `user.lastName` | `email` identifies the user, and `id` is a stable identifier that doesn't change if their email does. Send all four — sign-in fails if any is missing. ## SP-initiated sign-in Users can start sign-in from Serval directly: 1. Go to `https://app.serval.com`. 2. Enter your work email. Serval detects your organization's SSO domain and redirects you to Okta. 3. Complete authentication in Okta. Serval returns you to the app, signed in. ## Troubleshooting * **"Profile domain does not belong to the target Organization"**: the signed-in user's email domain isn't verified on your Serval organization. Verify the domain under **Organization → Security**. * **"Invalid SAML Response"**: the Okta metadata Serval has doesn't match the app sending the assertion. This happens if you recreate the Okta app or rotate its signing certificate. Re-run **Configure SSO** in Serval and send the current Okta **Metadata URL** again. * **Sign-in prompts you to verify a domain**: the email domain you're signing in with isn't verified on the Serval organization. Add and verify it under **Organization → Security**. * **Locked out after enabling Require SSO**: if Okta sign-in is unavailable, an administrator can restore access through magic-link sign-in for guest accounts, or contact your Serval representative. Turning on **Require SSO** disables password and magic-link sign-in for members on your verified domains. Confirm SSO works end to end for at least one administrator before enforcing it. If sign-in still fails after these checks, reach out to your Serval representative or Serval support with the time of the attempt and the error message shown. # Org chart Source: https://docs.serval.com/sections/documentation/platform/org-chart Explore your organization's reporting lines and find where anyone sits in the hierarchy The **Org chart** shows how people in your organization report to one another. It's a visual map of managers and their direct reports, built automatically from the manager information Serval receives when it syncs your users. ## Where to find it **Organization workspace** Switch to the **Organization** workspace in the sidebar's workspace switcher, then select **Org chart**. This opens the org-wide view. **A person's profile** Open any user's profile and select the **Org chart** tab to see the same map centered on that person. The org chart is available to everyone in your organization except external guests. Guests who only submit requests don't see it. ## The org-wide view The Organization workspace view shows your whole organization as a single tree of reporting lines. Use **Find a person** to search for someone by name. Selecting a result pins that person's reporting chain into the tree and moves the view to them, so you can jump straight to any part of a large organization without losing the surrounding structure. ## A person's org chart On a user's profile, the **Org chart** tab focuses on that individual: * A reporting-line rail lists the person's management chain from the top of the organization down, along with their direct reports. * The main view can switch between **Lineage**, which shows just this person's chain and reports, and **Entire org**, which places them within the full tree. * Selecting anyone else in the view opens their details, and their name links to their own org chart, so you can move from person to person. ## Where the data comes from Reporting lines are populated from the manager and reporting information that arrives with your [user sync](/sections/documentation/platform/org-settings#security-sso-scim-and-domains) from connected identity providers and HR systems. If no reporting relationships have been synced yet, the org chart is empty until that data is in place. If someone's manager looks wrong or missing, correct it in the connected system that owns your people data. The next user sync updates the org chart. # Organization settings and security Source: https://docs.serval.com/sections/documentation/platform/org-settings Org-wide users, teams, groups, identity (SSO, SCIM, domains), API keys, audit logs, and support tokens This page covers **organization-wide admin** — users, teams, groups, security (SSO, SCIM, domain policies), API keys, and audit. Per-team options (channels, SLAs, labels) live in [Team settings](/sections/documentation/platform/team-settings). ## Organization settings Access organization settings by switching to the **Organization** workspace in the sidebar's workspace switcher, then selecting **Settings**. Only **Org Admins** can access organization settings. ### Users Manage everyone in your organization: * View all users and their org roles (Member or Admin), split across **Users** and **Deactivated** tabs * Invite new users * Deactivate users one at a time, or select several and deactivate them in bulk * On the **Deactivated** tab, select several users and reactivate them in bulk * Change organization roles Organization admins automatically have full access to the **Organization** workspace. This access is inherited from their organization role and does not require a separate workspace assignment. Demo organizations also support invitations to users outside Serval. Invited users follow the same sign-in and role rules as users in a standard organization. Demo organizations expire 30 days after creation, including when they have external members. ### Teams Create and manage teams: * Create new teams with a name and prefix * View team membership * Delete teams ### Groups Organize users into groups for easier management: * Create groups * Add/remove users from groups * Use groups for [assignment rules](/sections/documentation/ticketing/ticket-configuration/assignment), [assignment groups](/sections/documentation/ticketing/ticket-configuration/assignment-groups) on tickets, and access policies If you try to close **Create Group** after changing its name, members, or scope, Serval asks whether to **Save changes** or **Leave without saving**. Close the **Unsaved changes** dialog to keep editing. Org groups are managed once for the whole organization. Each team then chooses which groups it uses for ticket ownership and routing. ### Branding Personalize how Serval looks and what it calls its AI assistant across your organization. Open **Organization Settings** → **Branding**. **Organization URL** The read-only sign-in URL for your organization, with a copy button so you can share it with your team. Once your organization has moved to this URL, ticket and notification links that identify your organization open here. Older app.serval.com and app.eu1.serval.com links without organization information keep you on that host after sign-in. Opening the link again can reuse your session. You may need to sign in once on each host. **Help Desk Agent** Set the **name** and **logo** for the AI assistant that appears in tickets and conversations. A **Let teams set their own agent name** toggle lets individual teams replace the organization name with their own. Turning it off returns every team to your organization's name, and each team's choice is remembered, so turning it back on restores their previous names. The assistant also uses this name when it refers to itself in messages to requesters, such as the "If you need me again, just mention …" line after an escalation, on every channel except Slack. In Slack it @-mentions your Slack app, so Slack shows the app's display name. **Application branding** Set the **name** (it defaults to Serval) shown next to the logo in the sidebar, on the sign-in screen, in the end-user portal, and on the hosted form pages people open from a shared form link, and upload **light** and **dark mode logos**. If you upload only one logo, Serval uses it for both themes. Changes take effect once you save. Serval never removes your ability to clear a field and return to the default. ### New Request page Choose which cards employees see on the **New Request** page, where they start a request in the web app. Open **Organization Settings** → **New Requests**, then toggle each card: * **Request access card** shows the entry point for requesting role-based access to applications. * **Service catalog card** shows the catalog of predefined services and forms employees can submit. * **Knowledge base card** shows the link to browse published knowledge articles. Each toggle saves immediately. Hiding a card removes it from the New Request page for everyone in your organization. ### Security: SSO, SCIM, domains, and data redaction A guided in-product setup for both SCIM and SSO is found within **Organizations → Security**. Serval connects identity providers using SAML 2.0 via [WorkOS](https://workos.com/), including Okta, Google Workspace, Azure AD (Microsoft Entra ID), OneLogin, JumpCloud, PingFederate, and other SAML 2.0 compliant providers. #### SSO * Connect and review **SSO** for your identity provider (SAML via WorkOS). * Confirm **domain verification** and overall **SSO configured** status from the card. * Use **Require SSO** when everyone must sign in through your IdP. If your sign-in domain belongs to more than one organization that enforces SSO, you choose which organization to sign in to, then Serval redirects you to that organization's identity provider. An SSO session can open another organization that doesn't require SSO only if Serval recognizes the issuing provider as an SSO provider for your email domain. Otherwise, sign out and use a different sign-in method for that organization. An SSO bypass still lets you use your organization's own identity provider. To switch organizations, choose **Logout** from your profile menu and sign in to the organization you want to open. If Serval asks you to sign in again when opening an organization, sign out and start a fresh sign-in. Refreshing an older session does not replace this step. #### WhatsApp sign-in WhatsApp sign-in is rolling out to selected organizations. An organization admin can configure it when **WhatsApp sign-in** appears under **Security → Sign-in methods**. 1. Open the management team's Twilio connection in **Integrations**. 2. In **WhatsApp sign-in delivery**, enter the **WhatsApp sender number** and **Magic-link template Content SID**. Use an approved template with the login URL in variable 1, then select **Save settings**. 3. Follow **Sign-in is enabled under Security settings**. The **Ready** status means delivery is configured. **Not ready** means delivery isn't ready or its readiness couldn't be checked. Use **Set up Twilio connection** to review setup. 4. Once the status is **Ready**, enable **WhatsApp sign-in**. The toggle is disabled while sign-in is off and delivery is **Not ready**. You can still disable sign-in if delivery becomes unavailable after enabling it. When your organization enables the channel, its login page shows **Use phone number**. Enter your number with its country code and select **Send login link**. If your number isn't enabled yet, verify it on WhatsApp first, then try again. The confirmation is the same whether or not the number is eligible to receive a link. Where WhatsApp sign-in is enabled for your organization, each phone number needs explicit login trust. Existing, newly added, and imported numbers start untrusted. Enabling the channel doesn't trust your directory automatically, and SSO requirements still apply. An organization admin can provision trust through the API using an organization API key. These endpoints do not accept OAuth user tokens: 1. Use **List User Phone Numbers** to find the current record. Check its `e164`, `isPrimary`, and `label` fields instead of relying on list order. 2. Use **Set User Phone Login Trust** with `phone_number_id` and `verifiedForMagicLinkLogin: true`. An organization API key needs `users:manage`; team API keys and workflow workers can't grant login trust. 3. To revoke trust, send the same ID with `verifiedForMagicLinkLogin: false`. Workflows can inspect phone numbers and their login trust with `serval.common.listUserPhoneNumbers({ userId })`. Workflows cannot grant or revoke login trust. The `phone_number_id` is the same ID returned in the user's phone number records. Listing the current record before granting trust prevents a stale request from trusting a replacement number. Trust belongs to the user's exact phone number record. Removing and re-adding a number requires a new grant. When directory sync replaces or clears a primary number, it removes the old number from the user’s phone numbers and revokes its login trust. If the replacement number belongs to another user in your organization, Serval still removes the old number but leaves the replacement unassigned. Other secondary numbers remain available. Manually choosing another primary number preserves existing grants. You can list phone numbers and revoke login trust for deactivated users. You can't grant them new login trust. Reactivating a user doesn't restore trust that you revoked. Revoking trust prevents new sign-ins, including completion of links issued before revocation. It doesn't end existing browser sessions. Directory sync also clears messaging verification for the removed number. The removed record cannot receive a new verification grant; adding the number again creates a new, unverified record. Messaging verification is separate from login trust and expires automatically. #### Session timeout Set how long a sign-in may sit idle before Serval signs the user out, under **Session timeout** on the Security page. The setting applies to every member of your organization. * Choose a duration from 1 hour to 30 days. The default is **Never**: sessions stay signed in until the user signs out. * Activity means any request the user's browser makes to Serval. A tab left open counts as idle once the person stops interacting with it. * An idle session is revoked on its next request or token refresh, and the browser signs itself out with a notice on the login page. Signing in again starts a fresh session. The timeout is a ceiling on inactivity, not a fixed session length. Shortening it applies immediately to sessions that are already idle for longer than the new value. #### Data redaction Enrolled organizations can add custom credential patterns under **Security → Data redaction**. Organization Admins preview expressions against sample text, then save them disabled or enable them across the organization's help desk teams. See [Data redaction](/sections/documentation/platform/data-redaction) for supported patterns, scope, and propagation timing. #### SCIM SCIM keeps your IdP and Serval in sync for **users** and **groups**, via [WorkOS](https://workos.com/) Directory Sync. Supported providers include Okta, Microsoft Entra ID (Azure AD), Google Workspace, JumpCloud, OneLogin, Rippling, and other SCIM-capable IdPs. What SCIM controls: * **Creates and deactivates Serval user accounts** as people are added to or removed from your IdP. A user your IdP deactivated stays deactivated until your IdP re-provisions them or an org admin reactivates them. User syncs from other connected integrations can't reactivate them. * **Imports your IdP's group list** into **Org Settings → Groups**. * **Sets each user's organization-level role** — Org Admin or Org Member — based on the WorkOS role slug computed for them. The most common pattern is to map a dedicated IdP group (such as `serval-admins`) to the `admin` role in the WorkOS dashboard for the directory connection. See [WorkOS Directory Sync — Roles](https://workos.com/docs/directory-sync/guide/group-roles) for the dashboard steps. * **Links a person's alternate email addresses** to a single account, so someone reachable at more than one address is never split into duplicate users. See [Email aliases](#email-aliases) below. **SCIM controls identity. Serval controls team assignment.** SCIM keeps your user list in sync and decides who is an Org Admin vs. Org Member. **Team membership and team-level roles** (Manager, Agent, Builder, Viewer, Drafter, etc.) are configured in Serval — most commonly by adding a synced group to a team with a specific role under **Team Settings → Team Members → Add group**. Every member of that group then inherits the chosen role on that team, and adds/removes in your IdP flow through automatically. ##### Email aliases Some people are reachable at more than one address — for example a full-form mailbox (`jane.doe@company.com`) and a short-form or UPN (`jdoe@company.com`). To keep them as one Serval account instead of a duplicate per address, send every address in the standard SCIM **`emails`** array on the User resource. Mark exactly one entry `primary: true` and the rest `primary: false`: ```json theme={null} "emails": [ { "type": "work", "value": "jane.doe@company.com", "primary": true }, { "type": "work", "value": "jdoe@company.com", "primary": false } ] ``` Serval uses the `primary` address as the account's email and treats the others as **aliases**. A request or message that arrives from any of them — email, Slack, the help widget, or a connected integration — is attributed to the same person, and no new account is created. Each user's aliases are listed on their profile under **Identity aliases**. Aliasing keys on the addresses your IdP sends in `emails`, so it only covers addresses present in the SCIM payload. Set exactly one address as `primary` — that value becomes the account email shown throughout Serval. Contact Serval to enable identity aliasing for your organization. #### User Sync Domain Allowlist * Turn **domain filtering** on or off for your organization. * Add **allowed domains** so only matching email addresses stay in scope when users sync from connected directories and integrations. ##### Enforce domain filter After allowed domains are saved, **Enforce Domain Filter** appears at the bottom of the domain allowlist card. 1. Click **Check Users** to run a **dry run**. Serval lists which users would be deactivated because their email does not match the allowlist. 2. Review the dialog. The admin running the check is **never** included in deactivation. 3. Confirm to deactivate all non-matching users in one step. Users deactivated by enforcement remain deactivated while **domain filtering** stays enabled. Reactivation rules follow your domain policy until it changes. #### External Requester Domain Allowlist This allowlist controls **who can become an external requester** — someone outside your organization who reaches your help desk and does not yet have a Serval account. It applies on every channel that creates a requester on first contact: email intake, Slack, Microsoft Teams, and connected ticketing integrations such as Jira, Linear, Zendesk, ServiceNow, Freshservice, and Salesforce. When filtering is on, a first-time sender from an unlisted domain gets **no guest account, and therefore no ticket**. This applies even if a team marks that domain as trusted in its own email settings, so the org policy is the outer boundary. The check runs **once, when the account is created**. Requesters who already have a guest account keep filing tickets even if you later remove their domain, and removing a domain never deactivates anyone. To cut off an existing requester, deactivate the user directly under **Org Settings → Users**. Organization members are not affected by this allowlist. They are governed by the **User Sync Domain Allowlist** above. #### AI Response Domain Allowlist This allowlist controls **which external requesters Serval AI replies to**, separately from whether they can file at all. When filtering is on, a requester from an unlisted domain still gets a ticket, and your team still gets notified — Serval simply withholds the AI response and routes the ticket to a human. Unlike the requester allowlist, this is checked **live on every message**, so edits take effect on the requester's next message with no sweep. Use the two together to admit a domain but keep Serval quiet with them: add the domain to the **External Requester Domain Allowlist** and leave it off the **AI Response Domain Allowlist**. Organization members always receive AI responses. This allowlist applies only to external requesters. ### API keys Manage programmatic access to Serval: * Create API keys with a name and an expiration (1, 7, 30, 60, 90, or 180 days, or 1 year). Every key must expire, and 1 year is the maximum. * Client secrets start with `svl_secret_` followed by a type tag (`pk` for API keys, `wk` for self-hosted worker keys, `mk` for svmeta worker keys) and 49 alphanumeric characters, for example `svl_secret_pk_…`. Point your secret scanner at `svl_secret_(pk|wk|mk)_[0-9A-Za-z]{49}`. Keys created before this format existed keep working unchanged. * Optionally scope a key to specific permission bundles (for example, `tickets:read` or `workflows:run`) so it can only reach the endpoints those bundles cover. A key created with no scopes has full access. * Optionally restrict a key to specific teams so it can only reach resources on those teams. Leave the team list empty to allow all teams. * Review a key's configuration, and revoke keys you no longer need Team Managers can also create team-scoped keys from **Team Settings** → **API Keys** without an org admin. A manager-minted key is limited to the teams they manage and to the scope bundles their own role can grant: full access and admin-only actions (such as ticket deletion) stay org-admin only. ### Audit logs View a record of actions taken in your organization: * Filter by user, action type, or date range * Export logs for compliance Actions performed with an API key show **API Key** in the **Actor** column. Open the event details with the magnifying-glass button to find the key's identifier. CSV exports also include the identifier. Audit logs capture activity across the platform, including: * **Approvals**: approve, deny, timeout, automatic conclusion, and cancellation of approval requests * **Access reviews**: reviewer decisions (certify, revoke, skip) and review reopen or cancel * **Knowledge**: knowledge document and ingestion-configuration changes (create, update, publish, archive, delete) * **Identity and directory sync**: SCIM directory sync, MFA changes, and team-group role bindings Use the **action type** filter to narrow the log to a specific category. #### Stream audit logs to a SIEM Stream your organization's audit events to an external security information and event management (SIEM) system, such as Splunk or Datadog. After you connect a destination, Serval forwards every audit event it records to that destination. Each event includes the action, who performed it, what it affected, when it happened, and context such as the IP address and user agent. Where phone login is enabled, audit events record changes to its integration settings, login-link delivery attempts, and successful magic-link logins. Phone additions and removals through the user phone-number settings also record the actor and affected user. Delivery success means the messaging provider accepted the request; it doesn't confirm receipt on the phone. These events don't include login URLs, tokens, or phone numbers. Serval streams audit events through WorkOS. You add and manage the destinations in a WorkOS-hosted portal, so the supported destinations and their setup fields come from WorkOS rather than Serval. Security settings showing the SIEM Logging section with a Configure SIEM button SIEM Logging uses the same WorkOS organization that Serval provisions when you set up SSO. Set up SSO first so that organization exists, or the **Configure SIEM** button can't open the portal. Go to **Organization Settings** → **Security** and find the **SIEM Logging** section. Only Org Admins can view or configure SIEM Logging. Select **Configure SIEM**. Serval opens a WorkOS-hosted portal in the same browser tab and returns you to the Security page when you finish. In the portal, add and configure each log stream destination that receives your audit events. You can connect more than one destination. Streaming continues even if you turn off **Require SSO** or disable SSO login, so audit events keep reaching your SIEM during an incident. #### SIEM streaming metadata Each streamed event carries the action, actor, targets, and request context, plus a `metadata` object with the event's security dimensions. A key appears only when the event carries that dimension; the set of keys is additive-only — new keys may be added over time, but existing keys keep their name, meaning, and value format. | Key | Value format | | - | - | | `outcome_status` | Result of the attempted action: `success`, `failure` (validly rejected), `denied` (blocked by authorization or policy), or `error` (internal fault). | | `outcome_reason_code` | Machine-stable reason code for non-success outcomes, e.g. `permission_denied`. Suitable for keying detection rules. | | `outcome_reason_detail` | Human-readable detail for the outcome. | | `severity` | Event level: `trace`, `debug`, `info`, `warn`, or `error`. | | `justification` | Business reason supplied by the actor at action time, for privileged or sensitive actions. | | `field_changes` | Compact JSON array describing what changed: `[{"field": "...", "old": "...", "new": "..."}, ...]`. Long individual values are shortened and end in `…`. | Metadata values longer than WorkOS's 500-character limit are truncated (ending in `…`). `field_changes` is the exception: it is never cut mid-string — whole trailing entries are dropped until the array fits, so the value always remains valid JSON. Any event whose metadata had to be cut down carries an extra `truncated: "true"` key — so your pipeline can distinguish a complete record from a shortened one. ### Support tokens Enable time-bound access for Serval support engineers to assist with your tenant: * **Generate tokens** — Users can create time-limited support tokens from the profile menu (**Get support**). * **Automatic expiration** — Tokens expire after the configured duration with no manual cleanup required. * **Full audit trail** — All access performed via support tokens is logged for compliance and transparency. For steps, security details, and how to revoke access, see [Support → Support tokens](/sections/documentation/platform/support#support-tokens). *** ## Quick reference | I want to... | Go to... | | - | - | | Invite a new user to Serval | **Org Settings** → **Users** → **Invite** | | Create a team | **Org Settings** → **Teams** → **Create Team** | | Set a default triage team | **Org Settings** → **Teams** | | Change the AI assistant's name or logo | **Org Settings** → **Branding** | | Set the brand name and logos | **Org Settings** → **Branding** | | Choose New Request page cards | **Org Settings** → **New Requests** | | Set up SSO | **Org Settings** → **Security** | | Stream audit logs to a SIEM | **Org Settings** → **Security** → **SIEM Logging** | | Create an API key | **Org Settings** → **API Keys** | | Add someone to my team | **Team Settings** → **Team Members** | | Configure Slack channels | **Team Settings** → **Channels** | | Set SLA targets | **Team Settings** → **SLA** | | Create ticket labels | **Team Settings** → **Labels** | Steps that use **Team Settings** are documented in [Team settings](/sections/documentation/platform/team-settings). # Permissions Source: https://docs.serval.com/sections/documentation/platform/permissions Understand user roles at the organization and team level in Serval Serval uses a two-level permission system: **organization roles** control what you can do across the entire org, while **team roles** control what you can do within specific teams. ## Organization Roles Every user has one organization-level role that applies across all of Serval. | Role | Description | | - | - | | **Member** | Standard user. Can submit tickets, request access, and use Serval's help desk features. | | **Admin** | Full administrative access. Can manage users, create teams, configure organization settings, and access all teams. | | **Guest** | Limited external user. Typically, a guest is a user who emailed in from a domain that isn't allowlisted. Can only see and interact with the specific tickets they're associated with, and can't browse other tickets, teams, or internal data. | Most users should be **Members**. Reserve **Admin** for IT administrators who need to manage the platform. **Guests** are usually created automatically for external senders from untrusted domains. For more information, see [Email intake](/sections/documentation/helpdesk/email#untrusted-domains). Organization admins inherit access to the organization management workspace, including Catalyst sessions there. You don't need to join its management team separately. To add a new user, navigate to "Settings" and select "Invite User" --> add their email addresses, choose to make them admin or not and optionally add them to a Serval team *** ## Team Roles Within each team, users are assigned a team-specific role that controls their capabilities for that team. | Role | Description | | - | - | | **Read-Only Agent** | View tickets, journeys, and analytics for the team. Can't make any changes. | | **Agent** | Everything a Read-Only Agent can do, plus respond to and resolve tickets, add internal notes, create saved views, and retry or cancel workflows while handling tickets. | | **Viewer** | Everything an Agent can do, plus view-only access to workflows, skills, knowledge, access policies, rules, campaigns, and databases. | | **Drafter** | Everything a Viewer can do, plus draft (create and edit) workflows and skills. A Drafter can't run, publish, or delete them. | | **Contributor** | Everything a Drafter can do, plus run published workflows, create and edit forms, and run Background Agents. Can't publish or delete. | | **Builder** | Everything a Contributor can do, plus create, publish, and delete workflows and skills; run unpublished workflows; create Background Agents; install installable workflows; publish and delete forms and view submitted form responses; and manage rules, campaigns, knowledge sources, access policies, approval procedures, analytics dashboards, and databases. | | **Manager** | Everything a Builder can do, plus configure integrations and connected apps, manage team settings, SLAs, schedules, and visibility groups, run access reviews, override approvals, view audit logs, and archive tickets. | A user can be a Manager in one team and an Agent in another. Team roles are independent. The **Drafter** role is being rolled out gradually and may not yet be available in your account. ## Custom Team Roles When a built-in role doesn't have the capabilities you need, create a *custom role*. A custom role is built on top of a base role and grants additional specific actions. An example of a custom role is a base role of Agent with permission to also view and cancel workflow runs. Custom roles are configured per team, alongside the built-in roles. ### Create a Custom Role 1. Go to **Team Settings** → **Roles**. The page lists available built-in roles and any existing custom roles. 2. Click **Create role** to open the dialog. 3. Enter a **Name** and **Description**. 4. Select a **Base role**. The custom role inherits everything that base role can do. A role without a base role can't be assigned until you set one. 5. Under **Granted actions**, select the extra actions to grant. 6. Click **Create role** to save. Create a custom role dialog with Name, Description, Base role, and Granted actions grouped by area You can only grant actions that you already hold on the team, so a custom role can't be used to escalate beyond your own permissions. The **Granted actions** list is grouped by area. **Campaigns**, for example, exposes individual actions to view, create, edit, delete, and archive campaigns. Granting these to a custom role lets you delegate campaign work — such as letting an Agent create and send campaigns — without giving them the full Builder role. A role that can create campaigns can complete the campaign wizard (including selecting recipients and delivery channels) end to end. The **Change Management** area exposes the change-model, blackout-window, and change-ticket actions, so you can build a scoped "Change Manager" role that authors change models, manages blackout windows, and files changes without granting the full Manager role. The **Approvals** area exposes the **Override approvals** action, which lets a role approve or deny the current step of any of the team's approval requests without being one of its assigned approvers. The override spans tickets, workflow runs, and access requests. Previously reserved for Managers, this break-glass action can now be granted through a custom role without the full Manager role, and every override is recorded in the audit log. ### Edit a Custom Role Open the role from **Team Settings** → **Roles** to change its name, description, base role, or granted actions. Select **Save** after changing the name, description, or base role. Changes under **Granted actions** are saved separately with **Save granted actions**, which replaces the complete action selection and confirms with a **Granted actions updated** message. ### Edit a Built-in Role Where enabled for your organization, a team can also adjust what its built-in roles grant, without creating a custom role. Editing requires **Edit Team Settings**; members with only **View Team Settings** open the same dialog read-only. Go to **Team Settings** → **Roles** and select a built-in role. Actions the role grants by default carry a **Default** badge. Check an action to grant it to everyone who holds this role on this team, or uncheck a default to take it away from this role. Select **Save granted actions**. The change applies on the next permission check for every member with that role, including members who hold it through a group. Changes are per team: editing the Agent role on one team doesn't change Agent on any other team. A role with changes shows a **Customized** badge in the roles list and in its dialog, where **Reset to defaults** removes every change for that role. Only the actions listed in the dialog can be changed; the rest of a built-in role's permissions are set by Serval. Removing an action from a role removes that role's grant of it. A member who also holds the action another way, through a second role inherited from a group or through a custom role, keeps it. As with custom roles, you can only grant actions that you already hold on the team. Resetting a customized role re-grants the defaults you took away, so it also requires holding those. ### Assign a Custom Role Custom roles are assigned the same way as built-in roles. In the team members list, open a member's role dropdown. Selecting a custom role sets the member's base role automatically and attaches the custom permissions. A member holds one direct role grant at a time, but can additionally inherit roles through one or more groups. Changing a member's direct role doesn't remove any roles they inherit through groups. Custom roles can also be managed through the [Custom Role API](/api-reference/custom-role-api/create-custom-role). Create a role with its `team_id`, `name`, `base_role`, and the `granted_actions` it adds on top of the base role; the same endpoints list, update, and delete a team's custom roles. Updating a role replaces its full set of granted actions, and deleting one leaves its members on the team with the role's base role. Groups can also be bound to a custom role through the [Team Group API](/api-reference/team-group-api/create-team-group). Pass `custom_role_id` when creating or updating a team group; the binding's `role` is set to the custom role's base role and can be omitted. Updating a team group with a built-in `role` and no `custom_role_id` replaces any custom role the group held on that team. Who can manage custom roles: * Viewing the Roles page requires **View Team Settings**. * Creating, editing, deleting, and assigning custom roles requires **Edit Team Settings**, which is typically a Manager. * Through the API, these changes need an organization API key with the `teams:manage` scope, or a user sign-in with organization-level team management. Signed in as a user, you also need **Edit Team Settings** on the team and can grant only actions you hold there. ## Permission Summary ### What Org Guests Can Do * View and reply to the specific tickets they're associated with * Upload attachments to those tickets * No access to other tickets, teams, users, or organization settings ### What Org Members Can Do * Submit tickets through Slack, email, or web portal * Request access to applications * View their own tickets and access requests * Use the catalog to browse access and catalog items ### What Org Admins Can Additionally Do * Create and manage teams * Invite and deactivate users * Configure organization settings (SSO, branding, etc.) * Access all teams regardless of team membership * Manage API keys * Share a [database](/sections/documentation/databases/administration) with the entire organization (team Managers can share with specific teams, but only an org admin can share org-wide) ### What Team Read-Only Agents Can Do * View all tickets and journeys associated with their team * View team analytics and dashboards * View saved views, workbench threads, and the archive * Can't edit tickets, add notes, or change configuration ### What Team Agents Can Additionally Do * Respond to, update, and resolve tickets * Create internal notes * Create and edit saved views * Retry and cancel workflows while handling tickets * View native knowledge base pages ### What Team Viewers Can Additionally Do * View workflows and skills (read-only) * View knowledge sources, databases, and entities (read-only) * View access policies, approval procedures, rules, and campaigns (read-only) ### What Team Drafters Can Additionally Do * Create and edit workflows and skills (can't run, publish, or delete them) * Create and edit native knowledge base pages and tags (can't delete or archive) ### What Team Contributors Can Additionally Do * Run published workflows * Run workflows on behalf of other team members * Create and edit forms, including preview (can't publish, delete, or view submitted responses) * Can't publish, delete, or run unpublished workflows * Edit and run Background Agents (creating one requires the Builder role) ### What Team Builders Can Additionally Do * Create, publish, and delete workflows and skills * Run unpublished workflows * Create Background Agents * Publish and delete forms, and view submitted form responses * Install and configure installable workflows * Share workflows with other teams * Create and edit rules and [campaigns](/sections/documentation/campaigns/overview) * Edit knowledge sources * Create and edit access policies and approval procedures * Create and edit databases and entities * Create and edit analytics dashboards ### What Team Managers Can Additionally Do * Configure integrations and connected apps * Manage team settings * Manage SLAs, schedules, and visibility groups * Run [access reviews](/sections/access-management/access-reviews) and override approvals * Manage change models * View audit logs * Archive, trash, and permanently delete tickets ## Managing Permissions ### Changing Organization Roles 1. Go to **Settings** → **People** 2. Find the user and click their name 3. Select **Member**, **Admin**, or **Guest** from the organization role dropdown 4. Save changes ### Changing Team Roles 1. Go to **Settings** → **Teams** 2. Select the team 3. Find the user in the team members list 4. Change their role to **Read-Only Agent**, **Agent**, **Viewer**, **Contributor**, **Builder**, or **Manager** (or **Drafter**, where enabled). Where custom roles exist, the same dropdown also lists them under **Custom roles** (see [Custom Team Roles](#custom-team-roles)). 5. Save changes Use your identity provider to automatically assign roles. Map directory groups to Serval roles in **Settings** → **Integrations** → **Directory Sync**. ## Capabilities Toggle Team managers can enable or disable specific Serval products per team using the **capabilities toggle** in team settings. This lets you control which features are available to a team — for example, you can disable Access Management for a team that only handles IT support tickets, or enable Workflows only for teams that need automation. Navigate to **Team Settings** → **Capabilities** to configure which products are active for each team. *** ## Org Admin Quick Join Organization admins can add themselves to any Serval team immediately when clicking a ticket link — without navigating to organization settings first. If an admin clicks a link to a ticket in a team they don't belong to, they can join that team on the spot and access the ticket. *** ## Common Questions Yes. Organization role and team role are separate. An Org Admin could be an Agent on specific teams if they only need to handle tickets, not configure that team. Users without team membership can still submit tickets and request access. They just can't view team visibility groups or use team-specific features. Access approvers are configured per access policy, not by role. Both Agents and Managers can be designated as approvers. # Platform Orientation Source: https://docs.serval.com/sections/documentation/platform/platform-orientation Navigate the Serval platform: workspaces, sidebar, teams, shortcuts, and search. This guide introduces you to the Serval platform interface, helping you understand where to find key features and how to navigate efficiently. ## Dashboard Overview When **Home** is enabled for your organization, it's the landing page for your personal workspace and for end users. Serval continues to honor a configured default team and restore your previous team or organization workspace. A default team takes precedence over the previous workspace. Links to a specific ticket or another page still open that destination. ### Your home page Home brings together your requests, approvals, Inbox updates, and journeys across teams. When enabled, **Home** replaces **New request** in personal and global navigation. From any workspace, open **Home** near the top of the sidebar, above **Inbox**. When Home isn't enabled, **New request** keeps its existing page or dialog behavior. Home shows only the sections you have permission to use. Start and send a request on Home under **What do you need help with?** Home reuses the personalized greeting and request editor. Let Serval route your request automatically, or select a team. Select a team to add file attachments. **Manual Ticket** opens the ticket form when you have permission to use it. The **Request access**, **Service catalog**, and **Knowledge** cards appear below the request editor when your permissions and organization settings allow them. Request options follow the teams available to receive requests. Home keeps a separate request draft. Team ticket creation uses the request dialog only where that separate feature is enabled; enabling Home doesn't enable it or change the existing request page's catalog options. On larger screens, request entry and tickets appear on the left. **Pending approvals**, **Inbox**, **Ongoing issues**, and **Your journeys** appear on the right. These sections stack on narrow screens. Review your work in these sections: * **My tickets**: Your submitted requests, with open tickets shown by default and the most recently updated first. The count reflects your search and filters and excludes deleted requests. Select a ticket to open it, or choose **View all** to see your requests. * **Assigned to me**: Tickets assigned to you, with open tickets shown by default and the most recently updated first. The tab remains available when no tickets match. Select a ticket to open it, or choose **View all** to see the full assigned list. * **Ongoing issues**: A summary of active major incidents you can access. Select it to open details for up to three incidents, with the most recently updated first. Select an incident card to open it. If more than three match, select **View all** in the dialog to open the ticket list filtered to active major incidents. * **Pending approvals**: Up to two decisions waiting for you in recent Inbox activity. Use **Approve** or **Deny** for a quick decision, or select an approval to open it in the [Inbox](/sections/documentation/platform/inbox). Decisions that require justification open the approval in Inbox so you can provide it. Opening these details marks the notification as read. Optional justification and delegation are available in Inbox when configured for the approval. Choose **View all** to review pending approvals. The count includes pending approvals beyond the two shown. A **+** after the count means older activity may contain more approvals. If older activity remains and no recent approvals are loaded, **View** appears instead of zero. * **Inbox**: Up to three recent updates, with the newest first. Pending approvals appear in their own section. Completed approval outcomes can appear here. If the preview has no updates but older activity remains, **Review your inbox** appears instead of an empty state. Select an update to open it in Inbox without your saved filters hiding the selection. This keeps your saved Inbox view unchanged. Choose **Open inbox** to return to your saved view. Switch between **My tickets** and **Assigned to me** in the ticket panel. Both tabs start with **Open**, which includes tickets waiting for work or already in progress. Each tab keeps its own search and filters when you switch tabs. Use **Search tickets** to find a ticket and the dropdown filters to narrow by status, priority, and ticket type. These controls stay visible below the tabs. Use the search field's **×** button to clear the search without changing your filters. The status dropdown offers **All**, **Open**, **Closed**, and **Closed in the last 30 days**. Use the last option to inspect recently completed work. For team, custom-date, due-date, SLA, or other advanced filters, choose **View all** to open the full Tickets view. The ticket list is read-only; open a ticket to make changes. When you have no open tickets, choose **View all tickets** in the empty state to include closed tickets. The panel loads 20 tickets at a time. Scroll within the panel to load more tickets automatically. **View all** opens the full list for the selected ticket tab with its search and filters, without changing your saved Tickets view. Tickets use the same summary layout on desktop and mobile: title, ticket number, status where your permissions allow, and the latest comment time or creation time. Open a ticket for requester, assignee, priority, and other details. The action-required indicator highlights tickets waiting on you. The journey section appears when you are the requester of a journey that isn't complete. It shows a journey's name and overall progress, including work assigned to you and other people, plus its due date when available. Select the highlight to open that journey. If you have two or three journeys, selecting the highlight opens a dialog where you can choose one. Journeys with unavailable progress also appear. Completed journeys leave Home. ### Navigation Structure The sidebar is organized around **workspaces**. A **workspace switcher** near the top lets you move between your personal workspace, the organization workspace (Org Admins only), and each team you belong to. Selecting a workspace swaps the navigation below it to the sections for that workspace, so you only see what's relevant to where you're working. These actions stay pinned above the switcher, available from any workspace: Submit requests and review your work, where enabled. Otherwise, this position shows **New request**. Your notifications and messages **Personal workspace** Your own work across teams: Tickets assigned to you Your access requests Browse and request access and services Knowledge articles Depending on your setup, the Personal workspace can also include **Access Review Tasks** (when you have access reviews assigned) and **Journeys** (when you have an active journey). **Organization workspace** Org Admins can open **Catalyst**, **Workflows**, and **Skills** for the organization management team from a grouped card in this workspace. **Integrations** appears separately below the card. Each item follows the management team's permissions; Catalyst also requires the Catalyst capability. You can pin these pages for quick access in the production environment. The **Analytics** and **Settings** items are visible to **Org Admins** only. **Org chart** is available to everyone in your organization except external guests. Metrics across all teams, with no team filter Explore reporting lines and find anyone in the organization Org settings and security: users, teams, SSO, SCIM, domains, API keys, audit **Team workspaces** Switch to a team to see that team's tools, grouped so related features sit together. The team's automation tools sit together at the top: Build automations from natural language Deterministic workflows for any action Guidance for AI agent behavior Proactive agents that discover problems A **Service Management** group holds the everyday pages: The team's ticket queue Import catalog items from connected systems Broadcast messages and collect responses Articles and documentation The team's remaining sections follow as their own items: Manage access roles and reviews This team's metrics and dashboards This team's active journeys Assets and CMDB Connected apps Team-level settings If you don't see any team workspaces in the switcher, you either haven't been added to a team yet, or no teams have been created. Ask an Org Admin to create a team or add you to one. **End users** People who aren't part of a team workspace, such as employees who only submit requests, see a simplified sidebar with no workspace switcher: **New request**, **Inbox**, **Tickets**, **Access**, and **Service catalog**. When enabled for your organization, **Home** replaces **New request** in this sidebar and is your default landing page. **Profile menu** Your profile sits at the bottom of the sidebar. Click your **name or avatar** to open your profile, or click the **more (⋮)** button next to it to open the profile menu: Switch between light, dark, or system mode Replay the guided product tour Set the Serval UI display language. Saved to your account. See what's new in Serval Open the Serval documentation Reach Serval support Sign out of your account Collapse the sidebar entirely for more screen space. Hover the edge to peek at it, and it stays collapsed as you move around the product until you reopen it. ## Teams: How Serval is organized Serval is built around **team workspaces,** which often correspond to teams in your company (for example IT Support, Security, or HR). Workflows, skills, knowledge, access management, integrations, and the majority of other automations are configured per team. Tickets are routed to teams, and permissions are team-scoped (you might be a Manager on one team and an Agent on another). You need **at least one team** before you can set up most team-scoped capabilities (workflows, access, Skills, automations, and similar). Read **Teams** for why teams matter, typical examples (IT, Security, HR, Finance), and step-by-step help to create your first team. ## Quick Actions Common tasks you can do from anywhere in Serval: | Shortcut | Action | | - | - | | `C` | Create a ticket | | `/` | Focus the search box on the current page | | `?` | Show all keyboard shortcuts | | `⌘K` / `Ctrl+K` | Open the command palette | | `J` | Next ticket, in a ticket list | | `K` | Previous ticket | To move between pages (tickets, workflows, team settings, and more), open the command palette with **⌘K** and start typing. Open a ticket to reveal ticket-specific shortcuts (assign, label, set status, reply, and more), or press `?` anywhere for the full, context-aware list. ### Command Palette Press **⌘K** (or **Ctrl+K** on Windows and Linux) to open the command palette. The command palette provides quick access to navigation, actions, and search from anywhere in Serval: type to find tickets, workflows, teams, or run commands without navigating through menus. ### Keyboard Navigation Between Tickets When viewing a ticket list, press **J** to move to the next ticket and **K** to move to the previous ticket. When you navigate back to the list, Serval returns you to the same position. ## Search Press `/` to focus the search box on the current page, such as the ticket list or app list. To search across Serval for tickets, workflows, teams, and more, open the command palette with **⌘K** (**Ctrl+K** on Windows and Linux). ### Search Tips * **Ticket search**: Search by ticket number, requester name, or content * **People search**: Find users by name or email * **Workflow search**: Search by workflow name or description * **Filters**: Add `type:ticket` or `status:open` to narrow results Use natural language in search. Try "password reset tickets from last week" to find relevant results. # Product security Source: https://docs.serval.com/sections/documentation/platform/product-security Security model for AI-assisted automation: isolated agents, deterministic workflows, and segregated teams with RBAC at the org and team level **Serval is an AI company that trusts AI only where it has to.** We treat the AI as a **probabilistic** component surrounded by deterministic enforcement. The hard security guarantees come from the infrastructure layers around the model, not from trusting the model to behave correctly. Here's what that actually means in practice. ## Property 1: Separation between agents We maintain a **strict separation** between two dedicated agents with very different jobs. They do **not** share context. ### Help desk agent **The help desk agent** handles end-user conversations. It can use your [knowledge base](/sections/documentation/knowledge-base/overview) and invoke **published** [workflows](/sections/documentation/workflows/overview), but it **cannot** create, edit, or change workflows in [Catalyst](/sections/documentation/catalyst/overview). **Administrators control the full surface area** of what it can use: knowledge sources, which workflows it may run, [access management](/sections/access-management/overview) tools, [Skills](/sections/documentation/skills/overview), and anything else exposed to help desk. It only gets tools your team **explicitly** turned on. ### Automation agent **The automation agent**, [Catalyst](/sections/documentation/catalyst/overview), is **separate**. It is for creating and configuring automations. It has **no** access to end-user ticket context and operates in a **different environment** from the help desk. ### What this isolation gives you Because the agents are isolated, a conversation in one [ticket](/sections/documentation/ticketing/overview) stays isolated from other tickets. Workflow runs are isolated in execution: one run cannot see or influence another. So there is no path for someone in one chat to manipulate the help desk agent into **leaking another ticket’s context** or into **reaching the automation agent layer**. The help desk agent cannot author or modify workflows. Prompt text cannot override identity. The system uses the authenticated session, so "I'm Jane" in chat does not change requester identity. ## Property 2: Deterministic workflows you can own and audit The help desk agent can only use tools your team configured. Those tools are **deterministic, code-based** [workflows](/sections/documentation/workflows/overview) by default. When you publish a workflow, it runs as **fixed TypeScript** that executes as written. The model **cannot** modify, bypass, or alter a published workflow’s behavior. It can only invoke it with the parameters you defined. **An LLM appears in a run only if your team intentionally adds a step that calls one.** That is not the default; typical workflows are fully deterministic end to end. A few things follow: * **No LLM in the default runtime path.** The automation agent’s job is to help translate intent into workflow code **during [authoring](/sections/documentation/workflows/Configure/build-guide)**. After publication, the same workflow runs the same way unless you explicitly put a model (or other non-deterministic) step inside the workflow. * **Real code you can edit and review.** Workflows live as TypeScript with **in-product [version history](/sections/documentation/workflows/Manage/versioning)** (timestamps, authors, restore). Teams can also use the [CLI](/sections/cli/overview) to pull and push workflows and keep them in Git: read them, diff them, and hand them to a security reviewer the way you would **application code**. * **Full audit trail.** Every published workflow version is tracked with timestamps and authors, and you can restore prior versions. Every workflow run is logged step by step with inputs, outputs, and status in [run history](/sections/documentation/workflows/Run/run-history). Beyond workflows, every API call is audited, including [access management](/sections/access-management/overview) actions such as role changes, profile updates, and approvals, plus integration configuration and admin settings changes. Logs are exportable. ## Property 3: Organization- and team-level segregation, roles, and controls Serval layers controls at two levels. Your organization governs cross-team access and identity, while each [team](/sections/documentation/platform/teams) is its own isolated environment with workflows, knowledge, [integrations](/sections/integrations/overview), policies, approvals, and RBAC. Controls at both levels are enforced independently. Team-level permissions cannot widen what your organization has scoped. ### Organization-level controls In [Organization settings](/sections/documentation/platform/org-settings), organization admins define cross-team identity and access boundaries for your entire Serval account. [Access Profiles](/sections/access-management/configuration/access-profiles) enforce eligibility based on user and group attributes, including who can request access to apps, resources, and roles, and who can run scoped workflows across teams. Organization Admins can also extend built-in secret scrubbing with [custom data redaction rules](/sections/documentation/platform/data-redaction) for internal credential formats in help desk messages. ### Team-level controls Every team in Serval is its own isolated environment, with its own workflows, knowledge, integrations, policies, access, roles, and approvals. Configure much of this under [team settings](/sections/documentation/platform/team-settings). Within each team, RBAC applies at every layer: the team itself, its integrations, API behavior, who can build, [workflow execution scope](/sections/documentation/workflows/Configure/execution-scope), and approvals. #### Integrations and API **API scoping per team.** When a team connects an [integration](/sections/integrations/overview), you define exactly what scopes Serval gets access to. That ceiling is set at setup and no workflow on the team can exceed it, regardless of what workflow code requests. **API credentials never touch the model.** When a workflow calls a connected service, the request flows through our integration proxy, which confirms the caller is a worker (not an end-user browser), validates that the integration belongs to the requesting team, and injects credentials server-side. Workflow code never sees API keys or OAuth tokens. #### Team roles (RBAC) Team roles are scoped per team and enforced independently from organization roles. For the full role matrix and capabilities, see [Permissions](/sections/documentation/platform/permissions). #### Workflows **Team-scoped execution.** Every workflow is scoped to a team or to the org. A team-scoped workflow is invisible to anyone outside that team, including the help desk agent serving other teams' users. **Custom conditions in code.** Workflow code can restrict execution based on the requester's location, department, employment type, or anything else in your user data. **Approval procedures.** Each workflow can require individual approvers, group approvals with an optional quorum, manager approvals, multi-step chains, or automated approval logic based on business rules. These are hard-coded into the workflow, not optional at runtime. See [Approvals](/sections/documentation/workflows/Configure/approvals). ## Compliance See the [Serval Trust Center](https://trust.serval.com/). *** ## FAQ Here are straightforward answers to questions we hear often. For more detail on workflows or access management, see [Workflow organization](/sections/documentation/workflows/Manage/organize#faqs) and the [Access management quickstart](/sections/access-management/admin-quickstart#faqs). ### Mistakes, hallucinations, and destructive actions Natural-language replies can vary, but **anything that changes a system or record goes through a published workflow** you control. Those workflows run the same way each time (unless you add a step that intentionally uses a model). You can add **approvals**, limit **inputs**, and set **who can run** a workflow so sensitive actions are explicit. Learn more in [Property 2](#property-2-deterministic-workflows-you-can-own-and-audit) and [Approvals](/sections/documentation/workflows/Configure/approvals). **Your administrators decide what gets built.** They publish **deterministic workflows** and configure **controls** (for example [approvals](/sections/documentation/workflows/Configure/approvals), [execution scope](/sections/documentation/workflows/Configure/execution-scope), integration permissions from the [apps you connect](/sections/integrations/overview), and team boundaries). Those layers restrict AI-assisted flows from triggering changes outside what you designed, so consequential actions stay inside reviewed automation rather than improvised model behavior. **[Agent separation](#property-1-separation-between-agents)** keeps chat and authoring in different environments. End users cannot bridge that boundary by prompting: they cannot reach workflow authoring, widen app access, or pull credentials through the conversation. Requester identity still comes from the authenticated session. Read [Property 2](#property-2-deterministic-workflows-you-can-own-and-audit) and [Property 3](#property-3-organization-and-team-level-segregation-roles-and-controls). **Talking to the AI does not by itself change your systems.** Updates run through your connected apps using the permissions you approved at setup. Combine **team-only workflows**, **who can run** a workflow, logic inside the workflow (for example who is targeted), and **approvals** so important changes only happen through automation you have reviewed. See [Execution scope](/sections/documentation/workflows/Configure/execution-scope) and [Approvals](/sections/documentation/workflows/Configure/approvals). ### Human control and automation Add **approvals** where you want a human sign-off: single approver, group, manager chain, multi-step, or rule-based. The help desk only **runs** workflows you already published; it does not invent new integrations or side effects beyond what you built. More in [Approvals](/sections/documentation/workflows/Configure/approvals) and [Property 3](#property-3-organization-and-team-level-segregation-roles-and-controls). Access follows the **apps and rules you configured**: connected systems, approved permissions, available entitlements, and logic in the workflow (including who the request applies to). For sensitive grants, require **approvals** so someone reviews before anything changes. [Permissions](/sections/documentation/platform/permissions) explains who on your team can build or change those workflows. The help desk chat is not where automations are written, and it does not expose passwords or API tokens for your connected apps. Whatever someone types cannot switch on new powers: the assistant only uses the workflows and tools your admins already gave it, and who the person is comes from their login, not from the message. Lines like "pretend I'm Jane" or "ignore policy" do not change their role, app permissions, or [who is allowed to run each workflow](/sections/documentation/workflows/Configure/execution-scope). It depends on **role**. **Contributors** can install [installable workflows](/sections/documentation/workflows/Configure/installable) but cannot author custom workflows from scratch. **Builders** and above can create and edit custom workflows. **Managers** configure integrations. Your organization decides who holds each role and who is invited. Details: [Permissions](/sections/documentation/platform/permissions). ### Data access and staying in scope **Only what you explicitly expose.** Admins choose which [knowledge](/sections/documentation/knowledge-base/overview), [workflows](/sections/documentation/workflows/overview), and tools the help desk can use. Organizations and teams are separated. When you connect an [integration](/sections/integrations/overview), **API scoping** is fixed at setup, so workflows cannot exceed the permissions your team already granted (see [Integrations and API](#integrations-and-api) under Property 3). Connections to your apps run outside the chat and credentials are not shown to the model. See [Property 1](#property-1-separation-between-agents) and [Property 3](#property-3-organization-and-team-level-segregation-roles-and-controls). You decide where data lives: **team-only** workflows, **who can run** them, and logic inside the workflow for who can be affected. For regulated data, align [knowledge](/sections/documentation/knowledge-base/overview) sources and app connections with your internal rules. A fuller picture of data categories is in the [Data elements inventory](/sections/documentation/data-elements-inventory); how **visibility** works is in [Execution scope](/sections/documentation/workflows/Configure/execution-scope). Share **only** the [knowledge](/sections/documentation/knowledge-base/overview) and tools that team needs, put risky steps in **published [workflows](/sections/documentation/workflows/overview)** (not open-ended chat), and use **[approvals](/sections/documentation/workflows/Configure/approvals)** when your policy requires human review. Serval provides team boundaries and repeatable automation; you decide what to connect and who can run it. ### Auditing what happened Every published version shows **who** published and **when**. Each **run** stores inputs, outputs, and status, and you can **export** history. That is your record of what automation did, separate from the conversation. See [Versioning](/sections/documentation/workflows/Manage/versioning) and [Run history](/sections/documentation/workflows/Run/run-history), and [Property 2](#property-2-deterministic-workflows-you-can-own-and-audit). **Yes.** Use different workflows for different risk levels: lighter approvals for routine tasks, stricter approvals or **team-only** visibility for sensitive changes (for example admin or directory updates). See [Approvals](/sections/documentation/workflows/Configure/approvals) and [Execution scope](/sections/documentation/workflows/Configure/execution-scope). ### Quick reference **Your administrators** choose [knowledge](/sections/documentation/knowledge-base/overview), published [workflows](/sections/documentation/workflows/overview), access tools, [Skills](/sections/documentation/skills/overview), and options like web search (including allowed domains, if you use it). See [Help desk agent](#help-desk-agent). **No.** Calls to connected apps use the **permissions you approved** when you set up the [integration](/sections/integrations/overview); a workflow cannot silently widen that access. Secrets stay on the secure execution side and are **not** passed into the help desk conversation. See [Property 3](#property-3-organization-and-team-level-segregation-roles-and-controls). See the [Serval Trust Center](https://trust.serval.com/). # Support Source: https://docs.serval.com/sections/documentation/platform/support Contact the Serval team, email support, and grant temporary access with support tokens Your Serval account includes a dedicated team ready to help you get the most out of the platform. *** ## Reach out to your account team The fastest way to get help is to contact the people on your account directly. Your account team knows your organization's setup, integrations, and goals — so they can provide tailored guidance and resolve issues quickly. If you're unsure who your account contacts are, check with your organization's Serval admin or reach out to us at the email below. *** ## Email support You can always reach us at **[support@serval.com](mailto:support@serval.com)**. Our support team monitors this inbox and will route your request to the right people. *** ## Support tokens When Serval needs to investigate an issue **inside your environment**, you can grant temporary access with a **support token**. Tokens are time-bound, user-initiated, and fully revocable—see below for how they work and how to manage them. ### Overview When you encounter an issue that requires direct investigation by Serval support, you can generate a **Support Token**. This token serves as a temporary "key" that allows our engineers to access your environment with the same level of visibility required to resolve your request. **Key features** * **User-initiated** — Admins, team managers, and agents can generate support tokens. * **Time-bound** — You choose how long access should last (for example 1 hour or 24 hours). Access automatically expires when the time is up. * **Access controlled** — Support token sessions have the exact permissions of the user that created them, no more, no less. * **Revocable** — You can revoke access at any time, immediately invalidating the token. * **Secure** — Tokens are generated securely on your device, and we use defense-in-depth techniques to ensure only Serval support engineers can use them. ### How it works 1. Click on your user in the bottom left to open the profile menu, then click **Get support**. 2. Enable **Support access** to generate a code. The code is automatically copied to your clipboard. 3. Optionally, adjust the expiration date. The expiration is saved automatically. 4. Provide the support token to Serval support. 5. As long as support access is enabled, Serval support engineers can redeem this token to access your account and organization. ### Managing access **Regenerating a token** — If you need to invalidate existing codes, click **Regenerate Token** in the Support Tokens section. This immediately invalidates all previous tokens and support sessions and creates a new token using the same expiration settings. **Revoking access** — You remain in full control. To immediately terminate access before the expiration time, turn off **Support access**. Once revoked, the support token is immediately invalidated, and all active support sessions are terminated. ### Security and compliance Support tokens ensure that: * **No permanent access** — Support engineers never have permanent access to your organization. * **Audit trails** — Every action performed by a support engineer while using a token is recorded in your organization's **Audit Logs**. * **Least privilege** — Support access is limited to the specific timeframe you authorize. # Team settings Source: https://docs.serval.com/sections/documentation/platform/team-settings Configure a team's members, roles, capabilities, ticketing, and access Most team settings apply to **one team** at a time. Open a team, then click **Settings** in the sidebar. Changing most settings requires the **Team Manager** role. Open your team settings Settings are grouped into **General**, **Access**, **Ticketing**, and **Infrastructure**. Some sections appear only when the related capability or feature is enabled for your team, so your list may be shorter than the one below. For **organization-wide** options (users, teams, groups, **Security** (SSO, SCIM, domains), API keys, and audit logs), see [Organization settings and security](/sections/documentation/platform/org-settings). *** ## General | Section | What it configures | | :- | :- | | **Your Team** | Team name, prefix, description, color, and an uploaded **avatar image** (which replaces the colored initials wherever the team appears), plus the team's **Users** and **Groups** | | **Pending actions** | Pending access approvals, workflow approvals, confirmations, and manual access provisioning and deprovisioning tasks for the team | | **Roles** | Custom team roles that grant a tailored set of permissions (if enabled) | | **Capabilities** | Per-team product toggles: turn features like Knowledge Base, Databases, Campaigns, Journeys, Document Signing, and Help Desk Agent Web Search on or off. Disabled capabilities are hidden from the team's sidebar | | **Catalyst** | Catalyst settings for building workflows and skills | | **Notifications** | Default notification behavior for the team | | **Schedules** | Business-hours [schedules](/sections/documentation/ticketing/ticket-configuration/schedules) used by assignment and SLAs | | **Archives** | Archived tickets and campaigns | | **Recently deleted** | Restore recently deleted tickets (if enabled), and workflows deleted in the last 30 days (a restored workflow comes back as an unpublished draft) | | **Tags** | The team's tag catalog | **User custom fields** is an organization-wide setting owned by a single team, the team that ingests users for your organization. On other teams the toggle is disabled. Hover over the info icon beside it to see the owning team. Turn it off there first to change ownership. ### Capability controls Under **Settings → Capabilities**, use each switch to enable or disable a capability. Clicking its name opens the related configuration page when available. A disabled switch can have an info icon beside it explaining its requirements. **Access management** groups **Reclamations** and **Access Reviews** beneath it. These controls are unavailable while Access management is off. **Test & Release** stays enabled when required by reviews, environments, or branches. For standalone teams that require reviews, its info popup links to **Reviews**, where **Approval settings** manages the requirement. Environments and branches always require Test & Release; their popup explains this without a configuration link. For **Help Desk Agent Web Search**, expand **Allowed sites** to manage permitted domains. Enter domains in the field and use each tag's remove control to remove it. Changes save automatically. ### Pending actions Open **Settings → Pending actions** to see the team's pending work, including actions assigned to someone else. You need permission to view settings, and the list only includes actions and destinations you can view. Filter between **Access approval**, **Workflow approval**, **Confirmation**, **Manual provisioning**, or **Manual deprovisioning**, or leave **All types** selected. Search by action title or reference and use **Sort by** to choose oldest or newest first. Click **Load more** to see additional results. **Manual provisioning** and **Manual deprovisioning** are open tasks from access management that need someone to grant or revoke access by hand. They appear alongside approvals and confirmations, and a task with no assignee yet shows as unassigned. Each row shows the existing ticket title and reference, who the action is waiting on, and a compact waiting duration such as **2h** or **3d**. Hover over the time to see the full date and time, including **Created** or **Requested** when the exact activation time is unavailable. Click anywhere on a row to open the ticket and use its existing controls. A workflow action created without a ticket opens its workflow run. Viewing an action here does not grant permission to approve it. Access-review campaigns and configuration reviews remain in their existing views. ## Access | Section | What it configures | | :- | :- | | **Access Policies** | Team [access policies](/sections/access-management/configuration/access-policies): approvals, expiration, and business justification | | **Access Profiles** | [access profiles](/sections/access-management/configuration/access-profiles) that control who can request which roles | | **Review Policies** | [Access-review](/sections/access-management/access-reviews) policies (if enabled) | | **API Keys** | Team-scoped [API keys](/sections/documentation/platform/org-settings#api-keys) a Team Manager can create, list, and revoke without an org admin | ## Ticketing | Section | What it configures | | :- | :- | | **Channels** | How the team receives requests: Slack and email intake | | **Help Desk Agent** | How the [help desk agent](/sections/documentation/helpdesk/agent-behavior) handles follow-ups and escalation | | **Evaluations** | Simulate and evaluate the help desk agent (Beta) | | **Statuses** | Custom ticket [statuses](/sections/documentation/ticketing/ticket-configuration/statuses) and the default for new tickets | | **Priorities** | Ticket [priorities](/sections/documentation/ticketing/ticket-configuration/priorities), colors, and defaults | | **Categories** | Ticket [categories](/sections/documentation/ticketing/ticket-configuration/categories) | | **Ticket types** | Configure [ticket types](/sections/documentation/ticketing/ticket-configuration/ticket-types) and their custom fields (formerly Custom Fields). Use **Capabilities → Ticketing** to turn optional types on or off, including Journey | | **SLA Rules** | [Service-level targets](/sections/documentation/ticketing/ticket-configuration/slas) by priority, with business hours | | **Labels** | Ticket [labels](/sections/documentation/ticketing/ticket-configuration/labels) for filtering and reporting | | **Ticket Visibility** | Visibility groups that limit which agents can see a set of tickets (if enabled) | | **Reference Documents** | A catalog of files the agent can attach to replies (if enabled) | | **Document Templates** | Templates for document-signing workflows, shown while the **Document Signing** capability is on. Turning the capability off hides this page but keeps your templates, so re-enabling restores them | | **Assignment** | [Assignment rules](/sections/documentation/ticketing/ticket-configuration/assignment) and default assignment, including [assignment groups](/sections/documentation/ticketing/ticket-configuration/assignment-groups) | | **Feedback** | Customer-satisfaction (CSAT) surveys | The **Help Desk Agent** settings include a **Help Desk Agent Name** field that overrides your organization's agent name for this team's replies, prompts, and notifications. Leave it blank to inherit the org-wide name. An org admin must first enable per-team agent names in Admin settings. ## Infrastructure | Section | What it configures | | :- | :- | | **Workers** | Self-hosted worker credentials and management (if self-hosted workers are enabled) | *** ## Quick reference (team) | I want to… | Go to… | | :- | :- | | Add someone to my team | **Settings → Your Team** | | See pending approvals and confirmations across my team | **Settings → Pending actions** | | Configure Slack or email intake | **Settings → Channels** | | Set up assignment rules and groups | **Settings → Assignment** | | Set SLA targets | **Settings → SLA Rules** | | Create ticket labels | **Settings → Labels** | | Turn a product on or off for the team | **Settings → Capabilities** | | Enable Journeys for the team | **Settings → Capabilities → Ticketing** | For org-wide tasks (invite users, create teams, SSO, API keys), use the table in [Organization settings and security](/sections/documentation/platform/org-settings#quick-reference). # Teams Source: https://docs.serval.com/sections/documentation/platform/teams How teams organize work in Serval—workflows, access, automations, routing, permissions, and creating your first team. Serval is organized around **teams**. A team represents a group that handles a specific type of request—like IT Support, Security, or HR. You must create at least one team before you can set up most product capabilities. **Teams are where the majority of configuration happens**—including automations, access, knowledge, and connected apps. ## Why teams matter * **Most team-scoped work lives on a team.** That includes **workflows**, **access** (access requests, policies, and provisioning tied to the team), **Skills**, **knowledge**, **integrations**, and **the majority of other automations**—each team has its own set of tools and connections. * **Tickets are routed to teams.** When someone submits a request, Serval routes it to the appropriate team. * **Permissions are team-based.** Users can be Managers on one team and Agents on another. ## Multiple teams Most organizations use several teams, matched to the kinds of requests they handle: | Team | Handles | | - | - | | **IT Support** | Hardware, software, general IT issues | | **Security** | Access reviews, security incidents | | **HR / People Ops** | Onboarding, offboarding, HR questions | | **Finance** | Expense reports, procurement | Start with one team (usually IT Support) and add more as you scale. You can reorganize later. ## Creating your first team 1. Go to **Settings** → **Teams** 2. Click **Create Team** 3. Enter a name and description, then choose the ticket routing scope 4. Add team members and assign roles (Agent or Manager) 5. Click **Create**, or **Continue** if guided setup is enabled for your organization Once you have a team, you can configure workflows, access, Skills, knowledge, integrations, and other team-scoped automations for that team. ### Guided team setup If guided setup is enabled for your organization, enter your team details, choose a color, and add members on **Team details**. Click **Continue** to open **Team setup**. Under **Start from**, choose **IT team**, **HR team**, **Security team**, or **Custom**, then adjust capabilities and ticket types. Knowledge Base is optional: it starts enabled for IT, HR, and Security, and disabled for Custom. Requests and Tasks are always enabled. Click **Create a team** to save your choices. For how teams appear in the sidebar and how to navigate between them, see [Platform orientation](/sections/documentation/platform/platform-orientation). For **Settings** on a specific team (channels, SLAs, labels, capabilities), see [Team settings](/sections/documentation/platform/team-settings). # Skills vs. Knowledge Source: https://docs.serval.com/sections/documentation/skills-vs-knowledge The one rule for deciding whether something belongs in a Skill or in your Knowledge Base Skills and Knowledge are the two ways you give Serval's help desk agent what it needs to resolve a request. The rule for telling them apart is one sentence. **Knowledge is information. Skills are instructions.** If it's a fact the agent looks up to answer a question, it's **Knowledge**. If it changes how the agent behaves, it's a **Skill**. *** ## The test Ask: **am I giving the agent a fact, or telling it how to act?** * **A fact** the agent uses to answer a question — "How much PTO do I get?", "What's our parental leave policy?" → **Knowledge** * **Instructions** that shape what the agent does — "Push back when someone asks for admin access; if they insist, run the access-request workflow" → **Skill** *** ## Examples | Put it in… | When it's… | Example | | - | - | - | | **Knowledge** | a policy or fact someone would look up | PTO policy, benefits overview, holiday schedule, expense limits | | **Skill** | a behavior or procedure the agent should follow | "For prod access requests, verify the requester's team, then run the access-request workflow" | | **Knowledge** | reference material, no action | "Our VPN client is Cisco AnyConnect; supported OSes are…" | | **Skill** | how to handle a situation | "If a user reports repeated VPN failures, collect their device details and escalate to IT" | The same topic can live on both sides. "The guest Wi-Fi password is `serval-guest`" is **Knowledge**. "When someone can't connect to Wi-Fi, walk them through these steps, then escalate if it still fails" is a **Skill**. Facts go in Knowledge; the steps for what to do go in a Skill. *** ## Learn more * [Skills overview](/sections/documentation/skills/overview) — how to write instructions for the agent * [Knowledge Base overview](/sections/documentation/knowledge-base/overview) — how to author and connect reference content # Always-Used Skills Source: https://docs.serval.com/sections/documentation/skills/always-used Ensure the help desk agent follows essential skills on every ticket Set important Skills as "always-used" to ensure the help desk agent includes them when responding to every ticket—not just tickets that match the skill description. ## When to Use Always-used skills are ideal for: * **Tone of voice** — Define how the agent interacts with users * **Ticket assignment rules** — Assign to specific owners based on content * **Compliance requirements** — Guarantee data protection on all requests * **Security protocols** — Ensure incident response procedures are followed ## How to Enable Toggle **Always use** when creating or editing a skill. When an always-used skill shapes the agent's response on a ticket, it appears in that ticket's **Relevant Skills**, even when the agent didn't cite it directly. This lets you see which mandatory skills were in effect. Keep always-used skills focused on universal rules. Too many always-used items can slow response quality—reserve it for skills that truly apply to every conversation. # Skills Source: https://docs.serval.com/sections/documentation/skills/overview Instructions that tell Serval's help desk agent how to handle specific scenarios Help Desk Skills was formerly called Guidance. Existing customers may still see "Skills (Guidance)" in the UI during the transition. The feature, your existing content, and all links are unchanged. Skills are instructions you write for Serval's help desk agent. When a user submits a request that matches one of your skills, the agent follows your instructions to respond—adapting its tone and approach while staying true to your procedures. Skills are unique because they combine agent instructions with deterministic workflows to create advanced automations. You build and edit skills in [Catalyst](/sections/documentation/catalyst/overview), Serval's automation agent. *** ## When to Use Skills Use **Skills** when you're giving the help desk agent instructions on **how to act**, **how to respond**, and **what context to consider** while helping an end user. Skills should focus on agent behavior and decision-making—not long-form reference content. Think of a Skill as "Something that you'd train your new help desk agents on." Skills are especially useful when you need the agent to: * Follow a consistent **tone and communication style** * Apply **language preferences** or formatting rules * Make decisions in a **multi-step troubleshooting flow** * Follow an internal **playbook** or **standard operating procedure** (triage, escalation, follow-up) * Handle edge cases or sensitive situations with the right framing Best Practice: Keep in mind that Skills should be focused on specific scenarios. Skill editor showing slow computer troubleshooting instructions *** ## Combining Skills with Serval Tools From a Skill, tag Workflows, Access Roles, Knowledge Base Articles and Users to help guide the help desk agent when responding to users. Writing that a database or tool is available in a Skill doesn't give the agent access to it. For steps that depend on a lookup or workflow, include a fallback for when that capability isn't available. For example, ask for information the agent can't retrieve or escalate to a human. A fallback must still respect approval, permission, and confidentiality requirements. A tag doesn't make an unavailable Workflow or Access Role callable. If the referenced item was deleted, disabled, unpublished, or isn't available for the request, the agent receives an unavailable reference. Update the Skill to reference an available item or provide a fallback. ### Skills & Workflows Skills and workflows **can** work together, but they don't need to be paired in every case. For straightforward actions with a single input and clear outcome (e.g., password reset, access provisioning), a workflow can usually run without an accompanying skill. A skill becomes important only when **extra context, judgment, or user interaction** is required. Use **a Skill with a workflow** when: * The agent needs **significant context** before running the workflow * The workflow outcome depends on **confirming details with the user** * A **second input** must be collected conversationally * There are **edge cases, policy constraints, or expectations** that need to be explained * The agent needs help **choosing whether or not** to run the workflow When a skill is used, the recommended pattern is: 1. **Create a workflow** for the single end-to-end action. 2. **Add a skill only when necessary** to explain *when* to run it and *how* to communicate with the user. ### Skills & Knowledge Base Both Skills and your Knowledge Base can answer user questions. They can be used for separate purposes, but you can also store knowledge in a Skill, if it best fits your company's processes. | Skills | Knowledge Base | | :- | :- | | Instruct the agent on **how to behave** | Provides **reference content** the agent can retrieve externally | | Tone, language rules, decision logic | FAQs, how-to articles, policies | | Active instructions ("do this, then this") | Passive information ("here's the answer") | | Tagging workflows and Serval automations | | | Self-healing information with [Serval Suggestions](/sections/documentation/suggestions/overview) | | When in doubt: if it tells the agent *how to act*, it's a Skill. If it tells the agent *what to say*, it's probably Knowledge Base content. If you don't have a formal Knowledge Base yet, start with a simple shared document or lightweight KB format and build from there. In the meantime, use Skills as an interim way to ensure the agent behaves consistently. *** ## Creating a Skill Navigate to **Skills** in the sidebar and click **New Skill**. Enter a **Name** (a short title the agent uses to identify this skill) and a **Description** (when this skill applies—helps the agent match it to requests). Add your **Content**—the actual instructions the agent follows. Write the skill as direct instructions to the agent, telling it what to do, what to ask, and when to trigger workflows. The skill editor supports rich text formatting including: * **Hyperlinks** — Select text and click the add link button, or paste a URL directly with CMD+V to insert clickable links * **@mentions** — Tag specific users by typing `@` followed by their name * **Knowledge base references** — Mention and link knowledge base articles directly in your skill content A skill's content is limited to 40,000 characters. Saving a longer skill is blocked, so keep the instructions focused and move reference material into a [knowledge base](/sections/documentation/knowledge-base/overview) or a separate skill. Link workflows to your skill using one of these methods: * **Type `@` in the content field** to search for and select an existing workflow inline * **Click the "+" icon** to either add a New Workflow or Browse Workflows (select from existing or installable workflows) * **Create a workflow directly** from the skill editor using the integrated side panel — build a new workflow without leaving the skill page * **Browse workflows from the sidebar** — filter by application, tag, and status to find the right workflow Selected workflows appear as actionable references the agent can execute when following your skill. Tag users in your skill by typing `@` followed by their name. Select the correct profile from the dropdown to reference specific team members. By default a skill reaches everyone. To restrict it, link one or more [access profiles](/sections/access-management/configuration/access-profiles#restricting-help-desk-skills) in the skill editor so only matching requesters receive the skill in the agent's context. Enable **Always use** if you want this skill included in every conversation, regardless of the user's request. [Learn more →](/sections/documentation/skills/always-used) Click **Save** to publish your skill. The agent will immediately begin using it for matching requests. You can organize Skills into folders from the Skills list, the same way you organize workflows, so a growing library stays easy to find. Changing or clearing filters keeps you in your current folder. When you apply a status filter such as **Always used**, or select a tag, each folder’s item count includes only matching skills directly inside it and subfolders containing matching skills. Folders with no matching skills anywhere inside them are hidden unless you search for a folder by name. *** ## Reviewing Suggested Changes When Serval suggests updates to an existing skill, you can review the changes using a diff view: * **Red strikethrough** highlights text that would be removed * **Green highlighting** shows text that would be added This compare view makes it easy to see exactly what changed before accepting or dismissing a suggestion. Serval also handles stale data — if someone else edits the skill while you're reviewing, you'll be notified to prevent accidental overwrites. *** ## Learn How to Build Skills for Your Organization * [Test example Skills](/sections/documentation/skills/use-cases) use cases for HR, IT, Ops, and Finance. * Use [Serval Suggestions](/sections/documentation/suggestions/overview) to automatically generate Skills based on existing tickets. Accept, configure, or deny these suggestions to build your skill library. Instruct Serval to remember knowledge or suggest a Skill when handling escalated requests. # Skill Use Cases Source: https://docs.serval.com/sections/documentation/skills/use-cases Examples of Help Desk Skills in action Examples of Skill configurations across common teams. Write each Skill as direct instructions to the agent—tell it what to do, what to ask, and when to trigger workflows. [Learn more about how Skills work first here](/sections/documentation/skills/overview), if you have not done so. ## IT Support ### Password Reset **Name:** Password reset help\ **Description:** User is locked out or forgot their password\ **Workflows:** Unlock Okta Account, Reset Okta Password ``` When someone asks about password reset: 1. First, determine if they're locked out or forgot their password - Locked out: They know their password but can't log in - Forgot: They don't remember their password 2. For lockouts: - Run the "Unlock Okta Account" workflow - Let them know they can try logging in again 3. For forgotten passwords: - Direct them to the self-service portal at password.company.com - If they can't access the portal (e.g., no phone for MFA), run the "Reset Okta Password" workflow - This will send a reset link to their personal email on file 4. If neither works, escalate to IT with details about what was attempted ``` ### Lost or Stolen Device **Name:** Lost or stolen device\ **Description:** User reports a lost, stolen, or missing company device\ **Workflows:** Remote Wipe Device, Force Password Reset ``` Treat all lost/stolen device reports as urgent. 1. Ask clarifying questions: - Was it a company device or personal device with company data? - When and where was it last seen? - Was the device encrypted and password-protected? - Were you logged into any sensitive apps (email, Slack, banking)? 2. For company devices: - Immediately run the "Remote Wipe Device" workflow - Run "Force Password Reset" to secure their accounts - Reassure them we're securing everything 3. Escalate to the security team: - Create a Security incident ticket with HIGH priority - Send a Slack DM to that person and their manager 4. Let them know next steps: - Security will follow up within 1 hour - IT will arrange a replacement device - They should monitor personal accounts for suspicious activity ``` ### Slow Computer **Name:** Slow computer\ **Description:** When someone says computer is slow\ **Workflows:** Get Iru Device for User, Restart Iru Device ``` 1. Provide basic troubleshooting (e.g., reboot, clear cache) 2. Run "Get Iru Device for User" to check device info 3. Check how long since last restart 4. If it's been more than 7 days since last restart: - Offer to restart their computer using "Restart Iru Device" - Let them know this may resolve performance issues 5. If troubleshooting doesn't help: - Check device age—if over 4 years, they may qualify for a refresh - Escalate to IT with device info and troubleshooting steps attempted ``` ## Security ### Phishing Report **Name:** Phishing or suspicious email report\ **Description:** User received a suspicious email or thinks they clicked a phishing link\ **Workflows:** Potential Compromise Response, Force Logout Sessions ``` Thank the user for reporting—this helps keep everyone safe! 1. Ask: Did you click any links or download any attachments? 2. If they DID click or download: - This is urgent—run the "Potential Compromise Response" workflow immediately - Run "Force Logout Sessions" to secure their accounts - Escalate to Security with HIGH priority - Tell them not to enter any passwords until Security clears them 3. If they did NOT click: - Ask them to forward the email to security@company.com - They can delete the email after forwarding - Thank them again for reporting 4. Common phishing signs to mention: - Urgent language or threats - Requests for passwords or personal info - Misspelled sender domains - Unexpected attachments ``` ## HR & People Ops ### Offboarding Request **Name:** Employee offboarding\ **Description:** Request to offboard a departing employee\ **Workflows:** Collect Offboarding Information, Offboarding Checklist, Transfer Files, Revoke All Access ``` For offboarding requests: 1. Run the "Collect offboarding information" workflow: - Employee's name and last day - Should their email be forwarded? If yes, to whom? - Who should receive access to their files and documents? - Any special handoff requirements? 2. Verify the offboarding is approved: - Check if HR has confirmed the departure - If not confirmed, ask the requester to have HR submit the request 3. Once confirmed, run the "Offboarding Checklist" workflow: - This schedules account deactivation for end of last day - Transfers files to designated recipient - Sets up email forwarding if requested - Revokes access to all systems - Generates audit report of their access 4. Let the manager know they'll receive a confirmation when complete ``` ## Finance ### Submit Reimbursements **Name:** Submit a reimbursement\ **Description:** User wants to submit a reimbursement or expense for repayment\ **Workflows:** Check Ramp Access, Request Ramp Access ``` Reimbursements are processed through Ramp. 1. Run "Check Ramp Access" workflow to see if the user already has a role that can request reimbursements 2. If they already have access: - Let them know they're all set to submit reimbursements - Skip to step 4 for next steps 3. If they don't have access: - Run "Request Ramp Access" access request - Share the available access roles - Suggest they request access to "Ramp Employee" so they can make continuous reimbursement requests - Let them know approval typically takes 1 business day 4. Once they have access, share next steps: - Log into Ramp via Okta single sign-on - Navigate to Reimbursements in the Ramp dashboard - Follow the instructions in Ramp to submit their reimbursement - Attach receipts for any expenses over $25 ``` ### New Vendor Request **Name:** New vendor setup\ **Description:** Request to add a new vendor or supplier\ **Workflows:** New Vendor Setup, Security Vendor Review, Finance Approval ``` New vendor setup requires approvals based on spend: 1. Collect required information: - Vendor/company name - What are we purchasing? - Estimated annual spend - Business justification - Requester's cost center 2. Route based on spend amount: - Under $10k/year: Run "New Vendor Setup" directly - $10k-$50k/year: Run "Security Vendor Review" first, then setup - Over $50k/year: Requires both Security and Finance approval 3. For software vendors, also ask: - Will they access company data? - Do they need system integrations? - These require additional Security review 4. Let them know typical timeline: - Under $10k: 2-3 business days - Over $10k: 5-7 business days for reviews ``` # AI suggestions Source: https://docs.serval.com/sections/documentation/suggestions/overview Let Serval analyze your tickets and suggest improvements Serval continuously learns from your ticket patterns and suggests ways to improve your help desk. When Serval identifies an opportunity for an automation from a ticket that was manually resolved, it creates a suggestion for you to review. This allows Serval to automate the automation and scale your Serval instance even faster. ## What Serval can suggest Document procedures for handling specific request types Improve existing skills based on new patterns Automate repetitive tasks Serval has identified Pre-built workflows that match your needs Integrations that could enhance your automations Add articles in **Notion**, **Confluence**, **Freshservice**, and **ServiceNow**, or update articles in **Slab** ## Where to find suggestions Suggestions can appear in these places: ### On source tickets For teams with background agent suggestions enabled, open the source ticket and view its **Activity** timeline. The timeline shows when Catalyst is working on suggestions for that ticket, then displays any suggestions the run produces. Expand a suggestion to review its details. Team members with permission to review Catalyst changes can accept or dismiss it from the timeline. Other team members who can view Catalyst suggestions see their decision status without action buttons. ### In Skills When you open your team's **Skills** section, a suggestions panel appears if there are pending suggestions. Click **Review** to expand and see the details. ### In Workflows On the **Workflows** page, click the **Review Suggestions** button in the header to see pending workflow and automation suggestions. The Skills and Workflows locations show the same pending suggestions—use whichever is most convenient. ## Reviewing suggestions in Skills and Workflows When you open suggestions, you'll see: 1. **Suggestion List** — All pending suggestions on the left 2. **Suggestion Detail** — The selected suggestion's content on the right 3. **Source Info** — The ticket(s) that triggered this suggestion For each suggestion, you can: | Action | What It Does | | - | - | | **Accept** | Creates the skill, workflow, or connection, or publishes a knowledge update into the connected source | | **Edit & Accept** | Modify the suggestion before accepting | | **Dismiss** | Remove the suggestion (won't be shown again) | Dismissed suggestions are saved in history so you can review past decisions. ## Suggestions for always-used skills Serval may suggest marking specific skills as "always-used" when it identifies instructions that should apply to every conversation — for example, compliance reminders, security procedures, or standard routing rules. Review these suggestions carefully, as always-used skills are included in every ticket resolution. *** ## How suggestions work 1. **Serval analyzes tickets** — As tickets come in, Serval looks for patterns 2. **Patterns trigger suggestions** — When Serval sees repeated questions or manual processes, it creates a suggestion. This includes suggestions to create custom workflows, install pre-built workflows, and connect new applications. 3. **You review and decide** — Accept helpful suggestions, dismiss ones that don't fit 4. **Your help desk improves** — Accepted suggestions become active skills or workflows ## Best practices Check suggestions at least weekly. The more you accept, the more Serval learns about what's useful for your team. Suggestions are starting points. Edit the skill or workflow to match your exact processes before accepting. If a suggestion isn't relevant, dismiss it. Serval won't suggest the same thing again, and you can always create a skill manually later. Review the tickets that triggered a suggestion to understand the context before accepting. ## Suggestion history View all past suggestions — including accepted and dismissed ones — by clicking the **History** tab in the suggestions panel. The history view shows every AI-generated suggestion with its outcome, so you can: * Track what automations came from suggestions * Revisit dismissed suggestions if your needs change * Audit how Serval's recommendations have shaped your help desk * Review the full timeline of accepted and dismissed suggestions across skills, workflows, and integrations # People Teams Automations Source: https://docs.serval.com/sections/documentation/team-solutions/People/people-team-examples Detailed workflow examples for onboarding, offboarding, HRIS automation, and People Ops processes This guide provides detailed workflow examples for People teams. For a quick-start guide, see [Serval for People Teams](/sections/documentation/team-solutions/People/people-team-starter). *** ## Onboarding Workflows Onboarding new employees involves coordinating across multiple teams and systems. These workflows automate common touchpoints. Automatically create accounts across your tech stack when a new employee starts: * Create email account in Google Workspace or Microsoft 365 * Set up communication accounts (Slack, Teams, etc.) and add to appropriate channels * Provision access to core tools based on role (Engineering, Finance, etc.) * Create entries in identity and security systems * Add to relevant distribution lists and groups **Example Trigger**: New employee detected in HRIS or manual request via Slack Coordinate laptop and equipment setup: * Create procurement request in your asset management system * Assign standard equipment based on role/department * Track shipping and delivery status * Notify IT when equipment is ready for configuration * Send welcome email with setup instructions **Example Trigger**: 2 weeks before employee start date Ensure new hires have everything they need on their first day: * Send welcome message with first-day instructions * Share onboarding checklist and training materials * Introduce to team via Slack channel * Schedule 1:1 with manager and People Ops * Provide links to benefits enrollment and policy documents **Example Trigger**: Employee start date Provision access based on the employee's department and role: * Lookup department and job title from HRIS * Apply appropriate access profile * Grant access to team-specific tools and resources * Add to security groups and permission sets * Document access granted for compliance **Example Trigger**: New hire detected or department change Ensure new hires complete benefits enrollment: * Send initial enrollment reminder with deadline * Provide links to benefits portal and documentation * Follow up if enrollment is incomplete * Escalate to People team if deadline is missed * Confirm enrollment completion **Example Trigger**: Scheduled based on start date and enrollment windows ### Example Prompt: Automated New Hire Setup > "When a new employee is added to our HRIS, create their Google Workspace account using their work email. Then add them to Slack and the #general and #announcements channels. Finally, send their manager a message with a link to their onboarding checklist." *** ## Offboarding Workflows Offboarding requires timely, complete access removal to maintain security. These workflows ensure nothing is missed. Systematically remove access when an employee departs: * Suspend or delete email account * Deactivate Slack account * Remove from all provisioned applications * Revoke SSO and identity provider access * Archive any personal data per retention policy **Example Trigger**: Termination detected in HRIS or manual request from People team Coordinate return of company assets: * Send instructions to departing employee * Track return status * Notify IT to wipe and inventory returned devices * Update asset records **Example Trigger**: Last day of employment Preserve institutional knowledge: * Export relevant documents and files * Reassign ownership of shared drives and projects * Transfer calendar events and meeting notes * Archive direct messages if needed for compliance * Notify team of transition **Example Trigger**: Last day of employment marked in HRIS or by manual request Ensure all offboarding steps are completed: * Create exit interview task for People team * Generate final payroll adjustments * Process benefits termination * Update HRIS employment status * Send confirmation to relevant stakeholders **Example Trigger**: Termination date entered in HRIS ### Example Prompt: Complete Offboarding > "Offboard Jane Doe, her last day is Friday." Serval looks up the employee in the HRIS, identifies all their provisioned accounts, and executes the revocation workflow—providing a complete audit log of what was removed. *** ## Employee Support Workflows | Workflow | Description | | - | - | | **PTO Balance Lookup** | Employees ask Serval for their current PTO balance; Serval queries the HRIS and responds | | **Manager Approval Routing** | Route requests (time off, expense, access) to the appropriate manager for approval | | **People Ops Ticket Triage** | Automatically categorize and route incoming People Ops requests to the right specialist | | **Anonymous Feedback Collection** | Collect employee feedback and surface trends to People leadership | | **PTO Request Form** | Structured form to request time off with automatic manager approval routing | | **Department Transfer Request** | Request to move to a new department with manager and People team approval | | **Address/Contact Update** | Self-service form to update personal information with verification | *** ## Lifecycle Management Workflows | Workflow | Description | | - | - | | **Promotion Processing** | Update access, titles, and systems when an employee is promoted | | **Department Transfers** | Adjust access and team memberships when employees change departments | | **Leave of Absence** | Manage temporary access suspension and reinstatement | | **Return from Leave** | Reactivate accounts and update systems when employees return | *** ## Reporting & Analytics Workflows | Workflow | Description | | - | - | | **Headcount Reports** | Generate weekly headcount summaries from HRIS data | | **Turnover Alerts** | Notify People leadership when turnover in a department exceeds thresholds | | **New Hire Summary** | Weekly digest of new hires starting, including their setup status | | **Access Audit Reports** | Monthly reports on who has access to sensitive systems | *** ## Recruiting Support Workflows | Workflow | Description | | - | - | | **Applicant Pipeline View** | Query your ATS for a summary of candidates by stage | | **Interview Feedback Reminder** | Send reminders to interviewers to submit feedback after interviews | | **Offer Letter Status** | Check status of pending offer letters and follow up as needed | | **New Requisition Alert** | Notify recruiting team when new job requisitions are opened | *** ## Related Documentation Quick-start guide for People teams Step-by-step guide to building workflows Add approval steps to your workflows Connect Serval to your tech stack # Serval for People Teams Source: https://docs.serval.com/sections/documentation/team-solutions/People/people-team-starter How People/HR teams can use Serval for onboarding, offboarding, employee support, and HRIS automation Serval empowers People teams to automate routine tasks, provide instant employee support, and streamline critical processes like onboarding and offboarding. *** ## Top Use Cases Answer employee questions instantly using your knowledge base—PTO policies, benefits info, handbook lookups, and more. Provision accounts, assign equipment, and send welcome materials automatically when new hires join. Revoke access across all systems, recover equipment, and complete exit checklists with a single request. *** ## Quick Start Get up and running in five steps: Before setting up People-specific integrations, your IT team should have already connected foundational systems to Serval—your identity provider (Okta, Google Workspace, etc.), Slack, and any core security tools. If these aren't set up yet, work with your IT team to complete the [IT team setup](/sections/documentation/team-solutions/IT/it-team-starter) first. Many People workflows depend on these foundational integrations for user provisioning and access management. Navigate to **Integrations** in Serval and connect your HRIS (BambooHR, Rippling, Workday, or others). This gives Serval access to employee data for automation. Once connected, you can use Workflows, Knowledge Base, and Skills to build automations that react to employee changes and requests. Upload or connect your People Ops documents—employee handbook, PTO policies, benefits guides, FAQs. Serval uses these to answer employee questions automatically. **Good sources to include:** * Employee handbook and code of conduct * Benefits and 401(k) information * PTO and leave policies * How-to guides (expenses, time off requests, etc.) Ask Serval a few questions employees commonly ask: * "What's our PTO policy?" * "How do I submit an expense report?" * "When is the next company holiday?" Start with a simple, high-value workflow. See [Create Your First Workflow](/sections/documentation/workflows/create-your-first-workflow) for step-by-step instructions. Here are some great first choices: **Onboarding:** * **New hire welcome message** - Send new employees a Slack message with links to the handbook and onboarding checklist * **Manager notification** - Alert managers when their new direct report starts * **Add to team channel** - Automatically add new hires to their department's Slack channel **Offboarding:** * **IT notification** - Alert IT when an employee's last day is approaching * **Equipment return instructions** - Send departing employees return instructions automatically *** ## Setting Up Your Help Desk Serval can serve as a private help desk for your People team, handling sensitive requests securely while answering general questions in public channels. ### Private Requests (Sensitive Information) For requests involving compensation, benefits changes, or personal information, employees should submit tickets privately: * **Slack DM**: Enable the DM feature so employees can message Serval directly * **Web Portal**: Employees can submit tickets through Serval's web interface Ticket threads in public channels sync between Serval and Slack by default so users can follow along in either thread. For sensitive requests, users can start DMs with Serval or use the web portal to keep conversations private. ### Public Channel (General Questions) Route general inquiries to a public helpdesk channel like #ask-people-team: * Policy and handbook questions * PTO and holiday schedule lookups * General onboarding questions A public channel builds a searchable knowledge base and reduces duplicate questions over time. *** ## Protecting Sensitive Information People teams handle sensitive employee data. Configure Serval appropriately: * **Restrict sensitive workflows** to private channels or DMs only—never expose salary, SSN, or personal contact information in public channels * **Add identity verification** for high-risk actions using an "always used" Skill that requires verification via your IdP * **Communicate clearly** to employees about where to submit sensitive requests Never configure workflows that return PII, compensation, or personal data to run in public channels. *** ## Next Steps Step-by-step guide to building workflows Detailed examples for onboarding, offboarding, HRIS automation, and more *** Need help getting started? Contact **[support@serval.com](mailto:support@serval.com)** for assistance. # Change Management Source: https://docs.serval.com/sections/documentation/ticketing/change-management Track and audit changes to internal configuration and physical assets with structured lifecycle management Change management in Serval helps you track, audit, and control changes made to your internal systems, configurations, and physical assets. Change tickets enforce a structured lifecycle from submission through implementation, with configurable approvals, automations, and transition conditions at every stage. *** ## What Is a Change Ticket? A **Change** ticket is a ticket type dedicated for managing modifications to your environment — software deployments, infrastructure updates, hardware swaps, configuration changes, or any controlled alteration to a system or asset. Unlike requests (which fulfill an ask) or incidents (which restore service), change tickets ensure that modifications follow a governed process with proper assessment, authorization, and post-implementation review. Serval supports three ITIL-aligned change models out of the box, plus the ability to create your own: Risk-assessed change that requires Change Advisory Board (CAB) approval before implementation Pre-approved, low-risk, routine change that follows a known procedure Expedited change that requires Emergency CAB (ECAB) approval for urgent situations *** ## Creating a Change Ticket Click **Create Ticket** from the ticket list or use the keyboard shortcut. In the dialog header, select **Change** as the ticket type. Choose which change model applies — for example, Normal, Standard, or Emergency. The model determines which statuses, approvals, and transitions apply to this change. Provide a title and description. You can also set priority, assignee, labels, category, due date, and any custom fields configured for that change model. Attach assets or configuration items that will be affected by this change, so you can track the impact. The ticket is created at the starting status and the lifecycle begins. If your team has no change models configured yet, you will see a prompt to set them up in **Team Settings → Ticket Types** before you can create change tickets. *** ## Change Models A change model defines how a category of change is handled: which statuses a ticket moves through, what approvals are required, what automations run at each step, and what conditions must be met to advance. ### Prebuilt ITIL Models Serval ships three prebuilt ITIL change models that your team can install from **Team Settings → Ticket Types**: | Model | Description | Approval | | :- | :- | :- | | **Normal** | Full lifecycle with risk assessment and authorization gates | CAB (Change Advisory Board) approval required | | **Standard** | Streamlined lifecycle for low-risk, routine changes | Pre-approved — no additional approval needed | | **Emergency** | Expedited lifecycle that skips assessment but retains authorization | ECAB (Emergency Change Advisory Board) approval required | During installation, you select the approvers (CAB or ECAB members) who will authorize changes. You can also configure a default assignee for change tickets. Prebuilt ITIL models have locked statuses and transitions to preserve compliance, but you can still configure approvers and default assignees. ### Custom Models If the prebuilt models don't match your process, you can create custom change models. There are two ways to build one: * **With the automation agent** — Describe the change process you want in natural language, and Serval builds the model for you — including statuses, transitions, automations, and custom fields. * **Manually in settings** — Go to **Team Settings → Ticket Types**, click **Add model** under the Change section, and configure each part of the model yourself. Custom models give you full control over every aspect of the change process. *** ## Ticket Lifecycle Every change model has a **lifecycle** — the series of statuses that a change ticket moves through from creation to closure. When a change ticket is created, it starts at the first status. From there, it can only move to statuses allowed by the configured transitions, ensuring changes follow your defined process. The prebuilt ITIL models come with standard lifecycle statuses already configured. For custom models, you define your own. For custom models, you can configure the full change process in **Team Settings → Ticket Types** — including the lifecycle statuses, how tickets transition between them, what automations run at each stage, and which custom fields are required. *** ## Automations at Each Status At every step in the lifecycle, you can attach automations that run as the ticket progresses. For example: * Trigger approvals * Send notifications * Run validation checks You can configure which automations run at each status from the change model settings. Each status can have multiple automations attached. The prebuilt ITIL models come with approval and tracking automations already wired to the appropriate lifecycle statuses. *** ## Transition Rules You can control how tickets move between statuses by defining transition rules. Each transition can have conditions that must be met before the ticket can advance — for example, requiring certain fields to be filled, a minimum time in the current status, or all of the ticket's tasks to be complete (each task done or canceled). Transitions can also be set to **automatic**, so the ticket advances on its own once the conditions are satisfied. *** ## Custom Fields Each change model can have its own set of custom fields tailored to the information needed for that type of change. For example: * A Normal Change might include fields for risk assessment, backout plan, and implementation window * An Emergency Change might include fields for justification and post-incident review * A Standard Change might only need a runbook link Configure fields per model in the **Fields** section of the change model settings. *** ## Impact Tracking Change tickets support tracking which assets and configuration items are affected by the change. You can attach relevant items during ticket creation or from the ticket detail view, giving your team visibility into what the change impacts. *** ## Related Pages * [Ticket Types](/sections/documentation/ticketing/ticket-configuration/ticket-types) * [Ticket Flows](/sections/documentation/ticketing/ticket-flows) * [Team Settings](/sections/documentation/platform/team-settings) * [Workflows](/sections/documentation/workflows/overview) * [Custom Fields](/sections/documentation/ticketing/ticket-configuration/custom-fields) * [Statuses](/sections/documentation/ticketing/ticket-configuration/statuses) # Incident Management Source: https://docs.serval.com/sections/documentation/ticketing/incident-management Track service disruptions with incident tickets, group related reports with AI, and promote a widespread outage to an approval-gated major incident Incident management is how you handle service disruptions in Serval. Use an **Incident** ticket to track and resolve a single issue, and a **Major Incident** ticket to coordinate a widespread disruption by keeping every affected ticket connected to it. Serval does three things automatically to keep this manageable: it **groups** related incidents under one report, it **detects** when an incident looks like a major incident, and it **links** new reports to an active major incident. Each is described below. *** ## When to Use an Incident Ticket Use an **Incident** ticket when normal service is not working and your goal is restoration rather than fulfillment. Common examples include VPN outages, SSO failures, email sync issues, and critical integrations timing out. Use a **Request** ticket for fulfillment work, such as access, equipment, or standard service asks. *** ## When to Use a Major Incident Use a **Major Incident** when one issue is affecting many people at once and needs a coordinated response, so their individual tickets can be tracked and updated together. Common examples include a company-wide VPN outage, an identity provider (SSO) going down, or a core application being unavailable for everyone on the team. *** ## Grouping Related Incidents When several people report the same underlying issue, Serval's AI Help Desk Agent recognizes that the new incidents are related and links them together, so your team sees one cluster instead of a pile of disconnected tickets. * **Everything links under the first report.** The earliest-created incident of the cluster becomes the **anchor**, and every related incident links to it. This anchor is stable — as more reports arrive, they attach to the same original incident rather than creating a competing group. * **The cluster is a star, not a chain.** Related incidents link to the anchor, not to one another, so there is always a single ticket that represents the group. * **Only open incidents count.** Resolved or canceled incidents are not pulled into a cluster. Grouping is about relatedness — it does not by itself decide that the issue is *major*. A cluster can stay a set of linked incidents, or it can be promoted to a major incident (manually or automatically) when the scope warrants it. Grouping runs on incidents specifically. A ticket is grouped after Serval classifies it as an Incident, so grouping always operates on the correct, post-classification ticket type. *** ## Promoting an Incident to a Major Incident Promotion turns an incident into the coordinating **Major Incident** for a widespread issue. In Serval this is not a silent type flip — it runs an installed, configurable **"Promote to Major Incident" workflow** so promotion can be governed, approved, and audited like any other change. ### Install Major Incident First Major Incident is an opt-in ticket type. A team manager installs it from **Team Settings → Ticket Types → Major Incident**. The install dialog collects two things and seeds the type in one shot: * **Statuses** — a dedicated status lifecycle for major incidents (see [Major Incident Statuses](#major-incident-statuses) below), pre-filled with a suggested set you can edit. * **Promotion approvers** *(optional)* — approvers who must sign off before a promotion completes. Leave it empty to promote with no approval. Installing seeds the major-incident status pool and model and installs the **Incident Promotion workflow** — a team-only workflow placed in an **Incident Management** folder and restricted to the team's managers. Install is a one-time action. After installing, you edit the model, statuses, approvers, and workflow directly — reinstalling is blocked so it never overwrites your team's later changes. ### Configuring the Promotion Workflow Promotion is powered by an ordinary Serval **workflow**, so you configure it the way you configure any other workflow — this is what makes promotion governable. On the **Major Incident** tab (Team Settings → Ticket Types → Major Incident) you'll see the **Incident Promotion workflow** card once the type is installed. From there: * **Edit workflow** opens it in the Workflows editor. Add an **approval step**, notifications, or any other steps your process needs. The card summarizes the contract: *the workflow runs when an incident is promoted, and the promotion takes effect when the workflow completes.* * Because promotion only reclassifies the ticket **after the workflow finishes**, an approval step in the workflow is a hard gate — the incident does not become a major incident until approvers sign off. * If you installed the type before the workflow existed, the tab shows an **Add promotion workflow** prompt to finish setup without touching your existing statuses and fields. The same Incident Promotion workflow runs for **both** manual promotions and [automatic detection](#automatic-major-incident-detection). Configure approvals once, and every promotion — however it was triggered — goes through the same gate and audit trail. ### Promote Manually With the **Promote to major incident** permission, open the incident's actions menu and choose **Propose major incident**. You can optionally record a **reason**, which appears inline on the type-change entry in the activity log. Promotion keeps the ticket's existing custom-field values and moves it into the major-incident status set, starting at that set's initial status. Behind the scenes this starts the promotion workflow rather than flipping the type directly. If an approval procedure is configured, the promotion waits for **approver sign-off** before the ticket is reclassified. ### Who Can Promote, and Approvals Two independent controls decide who is involved: | Control | What it governs | Default | Where to change it | | - | - | - | - | | **Promote permission** | Who can start a promotion | Team **managers** (the `promote_to_major_incident` permission) | Team roles and permissions | | **Approval procedure** | Who must sign off before the incident is reclassified | Whatever you set at install (optional) | The Incident Promotion workflow — set approvers at install, or [edit the workflow](#configuring-the-promotion-workflow) later | Where custom roles are enabled, you can grant **Promote to major incident** to an Incident Commander role with a lower base role, such as **Agent**. This permission lets members start promotion without **Manager** access or the **View ticket models** permission. Major Incident must be installed for the team, and configured approvals still apply. So "who can *propose* a promotion" and "who must *approve* it" are separate: you can let managers trigger promotions while still requiring, say, an on-call lead or an incident commander to approve before the change takes effect. Because promotion runs through a standard workflow, its approval, notifications, and audit trail behave like any other Serval workflow. A promotion is refused if one is already in progress for the incident, if the incident has another required workflow still pending, or if the incident is not eligible (for example, it is not an incident type). If a promotion is already running, a warning notification says "Promotion already in progress" with the guidance "Wait for the current promotion workflow to finish." Other blockers appear in an error notification explaining why the promotion can't start. *** ## Automatic Major-Incident Detection Once Major Incident is installed, Serval continuously evaluates whether an incident *should* become a major incident and proposes promotion for you — you do not have to build your own detection workflow. ### When Detection Runs An incident is (re)assessed whenever a signal that could change its severity changes: * It is **created** as, or reclassified to, an Incident. * Its **priority is raised**. * Its **affected-service blast radius is (re)computed** — for example, when a Tier-1 service is pulled into the set of impacted systems. Because assessment re-runs when priority is raised, an incident that starts low and escalates isn't missed — it becomes eligible the moment it crosses the priority threshold. ### How Serval Decides Detection is deliberately about the **nature of what's affected**, not a raw ticket count: 1. **Priority pre-gate.** Priority is how Serval captures an incident's **impact and urgency** (in ITIL terms, priority = impact × urgency), so it's the first thing the pre-gate checks. Only incidents at **High priority or above** are evaluated further — by default that means **High** and **Critical** — so Medium- and Low-priority incidents are skipped cheaply. The gate is based on the priority's **rank**, not its name, so it keeps working even if your team [renames its priority levels](/sections/documentation/ticketing/ticket-configuration/priorities). 2. **Scope and criticality judgment.** Serval weighs the **Configuration Items** the incident affects — their type and criticality tier — plus the blast radius reached through service dependencies. A single incident that takes down one **Tier-1 business service** can qualify on its own, while many reports about individual laptops or personal accounts will not. Serval can infer criticality even when a tier isn't explicitly set. 3. **Promote the right ticket.** If the incident belongs to a cluster, detection promotes the cluster's **anchor** (the first report), not a member — so the group gets one coordinating major incident. ### Always-Propose Rules Some teams treat certain incidents as major by policy and don't want Serval weighing in. On the **Major Incident** tab (Team Settings → Ticket Types → Major Incident), below the Incident Promotion workflow card, you can add **promotion rules**. An incident that matches an enabled rule is proposed as a major incident directly, ahead of the priority pre-gate and without the scope-and-criticality judgment. Each rule matches on one or more conditions, combined with AND / OR: * **Priority** * **Assignment group** * **Category** * **Label** * **Escalated** * **Requester group** * **Requester field**: a value on the requester's profile * **Schedule**: the incident arrives within a business-hours schedule A rule only changes what gets *proposed*. The Incident Promotion workflow and its approval gate still run, so an approver signs off before the ticket is reclassified, and a promotion someone already denied is never re-raised. ### What Makes an Outage a Major Incident Serval uses the definition ITIL and ServiceNow share: a **major incident is the highest-priority incident — high *impact* combined with high *urgency*** (ITIL Priority 1), causing significant business disruption and warranting a dedicated, coordinated response. A localized, low-severity, or routine issue is not a major incident, and when the evidence is thin or the call is borderline, Serval does **not** promote. To make that judgment, Serval weighs all the evidence on the incident: * **The affected Configuration Items (CIs).** Their type, name, and criticality tier when set (`tier_1` = revenue- or safety-critical). Serval infers criticality from the CI's name, type, and the incident text even when no tier is set — a shared production system, business-critical service, or vital business function reads as high impact, while a single low-criticality item like a personal device or individual account does not, *even in numbers*. * **The incident itself.** Its title and description — what is broken, how widely, and for whom. * **Blast radius.** How many downstream services sit in the affected CIs' dependency graph. A larger blast radius supports breadth, but is **not required** — one critical service down can be major on its own. * **Urgency.** Whether the damage is escalating or time-sensitive, or an SLA is breached or about to be. The ticket's **priority** is your team's own urgency/impact signal and feeds this. * **Severity & recovery.** A complete outage versus a minor or cosmetic degradation; whether there's no known workaround or the recovery time is unknown. * **Exposure.** Material financial, reputational, regulatory/compliance, data-privacy, security, or safety exposure. Serval promotes only when the incident is clearly **both high-impact and high-urgency**, and it returns a short reasoning that names the specific CIs and factors behind the call — which is exactly the [reason recorded on the activity log](#detection-proposes-people-approve). This is why the affected CIs matter so much: "one affected item" can be a company-wide identity provider **or** a single laptop. Serval judges the *nature* of what's affected, not the count — so keeping incidents' affected services accurate directly improves detection quality. ### Detection Proposes; People Approve When an incident qualifies, Serval starts the **same approval-gated promotion workflow** used for manual promotion. Automatic detection therefore *proposes* a major incident — if you configured an approval procedure, an approver still signs off before the ticket is reclassified. Serval also records a **user-facing reason** on the anchor ticket's activity log explaining why it was proposed (its priority and the services it affects). Detection is careful not to nag: * It never assesses or promotes a **resolved or canceled** incident. * It never **re-proposes** a promotion a person already acted on — if an approver denied a proposal, a later priority edit or blast-radius change won't ask them again. A human can still promote manually at any time. Automatic detection is a safety net, not a replacement for judgment. Managers can always promote manually, and approvals keep a human in the loop before any incident becomes a major incident. *** ## Major Incident Statuses Major incidents use their own status lifecycle instead of the generic To Do / In Progress / Done set, so the response tracks its real stages, such as Declared, Investigating, Mitigating, Monitoring, and Resolved. Configure these on the **Major Incidents** tab under **Team Settings → Statuses**, where you can add and edit statuses. Promoting an incident to a major incident moves it into the major-incident status set, starting at that set's initial status. *** ## How Incident Management Works in Serval A ticket comes in from Slack, Teams, email, web, or external sync. Serval can classify it as an **Incident**. Serval's AI links related incidents under the earliest-created report (the anchor), so duplicate reports of the same issue are tracked as one cluster. See [Grouping Related Incidents](#grouping-related-incidents). Your team sets status, priority, assignee, labels, and due date to establish ownership and urgency. For a widespread issue, a major incident coordinates the response. A user with the promotion permission can [promote manually](#promoting-an-incident-to-a-major-incident), or Serval's [automatic detection](#automatic-major-incident-detection) proposes promotion when an incident's scope and criticality warrant it. Either path runs the approval-gated promotion workflow, so an approver can sign off first. Once a major incident exists, Serval automatically links new related tickets on the same team to it and notifies those requesters that a major incident is underway. Your team runs remediation actions (including workflows), resolves the incident, and syncs updates across connected systems when configured. Updates on a major incident flow out to every linked ticket, and resolving the major incident closes the linked reports it was coordinating. Serval links related tickets automatically: its AI Help Desk Agent detects when a new ticket appears related to an active major incident, links it, and tells the requester in-thread that one already exists. Team members can also link a ticket manually from its **Linked Tickets** panel. Related tickets link **to a major incident**, not to one another. The major incident is the one ticket that every related report connects to; those reports are not linked to each other. Because every link points at the major incident, updating or resolving that one ticket is how you reach everyone who reported the issue. As a major incident changes, Serval surfaces its updates in each linked ticket's conversation, so requesters see the update wherever their ticket originated, such as Slack or Teams. Team members can also click the **broadcast** button (the megaphone) on a major incident's message composer to push a single status update to every linked ticket at once. After sending, broadcast messages keep a red highlight and a **Broadcast** badge in the ticket thread — the same way internal notes stay yellow — so you can tell at a glance which messages went out to every linked ticket. *** ## Related Pages * [Ticket Types](/sections/documentation/ticketing/ticket-configuration/ticket-types) * [Priorities](/sections/documentation/ticketing/ticket-configuration/priorities) * [Ticket Flows](/sections/documentation/ticketing/ticket-flows) * [Resolving Tickets](/sections/documentation/ticketing/resolving-tickets) * [Updating Ticket Properties](/sections/documentation/ticketing/manage-collaborate/update-ticket-properties) # Team routing & assignment Source: https://docs.serval.com/sections/documentation/ticketing/manage-collaborate/assignment-routing How tickets get to the right team and the right person Serval handles two levels of routing: getting tickets to the right **team**, and then assigning them to the right **person** within that team. *** ## Team routing Most channels are tied to a single team, so tickets from that channel go directly to that team. Routing only comes into play when a channel is connected to multiple teams or when a ticket is submitted without a team specified. Org Admins can designate a default triage team under **Org Settings → Teams** as the fallback when routing can't confidently pick among the candidate teams. Teams with **Team Visibility** off ([Team settings](/sections/documentation/platform/team-settings)) are omitted from automated routing and from requester team selectors. Single-team channels still route to their configured team. ### When routing happens * **Multi-team channels**: If a channel serves multiple teams, Serval uses AI to analyze the ticket content and route it to the best-fit team based on team descriptions * **Web app without a team selected**: When a requester submits via the web app without choosing a team, Serval routes based on content * **Ambiguous routing**: If Serval can't confidently pick among the candidate teams, the ticket goes to your org's **default triage team** when one is set and included in that set; otherwise it goes to the oldest candidate team. Write detailed team descriptions so AI routing can accurately match requests. Include the types of issues your team handles and relevant keywords. ### Manual routing Requesters can manually select a team when submitting via the web app, and team members can transfer tickets between teams at any time. *** ## Assignment Once a ticket reaches a team, it's assigned to Serval AI by default. Serval works the ticket automatically until it either resolves it or escalates to a human. ### How assignment works When a ticket is escalated to a human, either by the AI or manually, assignment is determined by your [assignment rules](/sections/documentation/ticketing/ticket-configuration/assignment). Assignment rules let you match on ticket category, priority, status, and schedule, then assign to users or an [assignment group](/sections/documentation/ticketing/ticket-configuration/assignment-groups). When a rule or default assignment targets a group, the ticket gets that owning group. Depending on the team's **Group member assignment** setting, Serval either round-robins a member as the individual assignee or leaves the ticket for human triage. If no assignment rules are configured and there is no default assignment, escalated tickets remain unassigned until someone manually claims them. To preview which rule would match before going live, use [Simulate assignment](/sections/documentation/ticketing/ticket-configuration/assignment#simulate-assignment) on **Team Settings → Assignment**. ### Assignment reasons Hover over a ticket's assignee to see the reasoning behind the assignment. Serval displays why a particular person was assigned, such as: * **Workload balancing**: Assigned based on current ticket load * **Expertise matching**: Assigned based on skills or category rules * **Manual selection**: Assigned by a specific team member This transparency helps teams understand routing decisions and identify when assignment rules need tuning. ### Manual assignment Tickets can be manually assigned or reassigned at any time from the list view, detail view, or chat. See [Updating Ticket Properties](/sections/documentation/ticketing/manage-collaborate/update-ticket-properties) for details. *** ## Cross-team transfers Transfer tickets to a different team when needed: 1. Open the ticket 2. Click **Transfer to Team** 3. Select the destination team The ticket gets a new number in the destination team's numbering system. Redirects are created so references to the old ticket number still work. When you transfer a ticket, it leaves your team's queue. The new team becomes responsible for resolution. *** ## Related Configure assignment rules based on category, priority, status, and schedule Own tickets by org group with round-robin or human triage How to manually assign and reassign tickets # Feedback Source: https://docs.serval.com/sections/documentation/ticketing/manage-collaborate/feedback Collect feedback on Serval's performance for resolved tickets Gather feedback from employees on how well Serval handled their support requests. Use this data to measure AI performance and identify areas for improvement. *** ## How feedback works When a ticket is marked as Done, Serval can automatically request feedback from the ticket requester. Pick a rating scale: * **Thumbs up/down**: Simple positive or negative * **Star rating**: 1-5 star scale Either scale can also ask for a written comment and accept file uploads, so requesters can send a screenshot or photo with their rating. Both are always optional for the requester — they can send a rating alone. Feedback responses are recorded on the ticket and aggregated in team analytics. Feedback collection is **disabled by default** and must be enabled for each team in the feedback portal. *** ## Eligibility Not all resolved tickets receive feedback requests. A ticket must meet these criteria: * Feedback is enabled for your team * Feedback hasn't already been requested for this ticket * The ticket passes the sampling rate filter (if less than 100%) Serval only requests feedback **once per ticket**. *** ## The feedback portal Each team has a dedicated feedback portal where managers can configure collection behavior. Go to **Team Settings** → **Feedback** to access it. The feedback portal lets you: * Enable or disable feedback for the team * Choose the rating scale (**Thumbs up/down** or **Star rating**) * Choose whether to also ask for a written comment * Choose whether to accept file attachments * Choose when to request Serval feedback (**Meaningful tickets** or **All tickets**) * Set collection frequency * Review all feedback received by the team ## Setting up feedback Go to **Team Settings** → **Feedback**. Toggle on **Request Feedback on Serval's Performance**. When collecting Serval feedback, set **Request feedback for Serval when** to **Meaningful tickets** or **All tickets**. Select the type of rating to collect: * **Thumbs up/down**: Simple positive or negative * **Star rating**: 1-5 star scale Toggle on **Also ask for a comment** to add an optional comment box alongside the rating. It works with either rating scale. Toggle on **Allow file attachments** to let requesters attach screenshots or photos. It works with either rating scale, with or without a comment box. Choose how often to request feedback from eligible tickets: * **Rarely (10%)** * **Sometimes (25%)** * **Often (50%)** * **Usually (75%)** * **Always (100%)** *** ## How users provide feedback When a ticket is eligible, Serval sends the requester a feedback prompt. In Slack, the requester answers in a single click — a thumb or a score — and the confirmation that replaces the prompt lets them go back in: **Change rating** when the team collects ratings only, or **Add comment or edit** when it also collects comments. In the Serval web app, including embedded web chat, a prompt that collects neither a comment nor files submits on the click. Otherwise the requester picks a rating, adds an optional comment and then submits. File attachments are available in the full web app; embedded web chat supports ratings and optional written comments. Files attached in Slack come through the feedback modal (the same one behind **Add comment or edit**), and are limited to 5 files of 8 MB each — Slack gives Serval about three seconds to store them before the modal closes. The web app takes files up to 50 MB. Attachments appear on the ticket alongside the rating and in the feedback portal. The message is only visible to the requester. After responding, the message updates with a confirmation. Custom Slack apps can opt in to requester-initiated feedback. Your app administrator must manually register a command such as `/serval-feedback` using the same webhook base URL as the app's existing slash command, with the path `/slack/commands/feedback`. Slack reserves `/feedback` for its own support command. The standard Serval app and generated app manifests don't register the feedback command. Once configured, your feedback command opens a feedback modal for your ten most recent tickets on teams that collect feedback, including tickets filed on your behalf. Select a ticket and wait for its rating form to load before submitting. Switching tickets resets the form to the selected ticket's saved feedback. The rating scale, optional comment box, and file input follow the selected ticket's team settings. Submitting replaces your existing rating for that feedback target. Feedback must be enabled for the team, but automatic sampling and lifecycle rules don't apply to volunteered ratings. In Microsoft Teams, `/feedback` replies that the command isn't available there yet. Feedback requests can be sent through Slack and Serval web experiences, including embedded web chat. Feedback responses can be viewed in the Serval web app on individual tickets and in team analytics. *** ## Submit feedback through the API Use `POST /v2/tickets/{ticket_id}/feedback` to record an answer from a customer portal or survey integration. The caller needs permission to update the ticket. Send either a `thumbs` response with `is_positive` or a `detailed` response with `star_rating` from 1 to 5. The response must match the team's configured rating scale. Both support optional `text_feedback`. ```json theme={null} { "thumbs": { "is_positive": true, "text_feedback": "My issue was resolved quickly." } } ``` The answer defaults to the ticket requester. API keys and workers can provide `user_id` to submit on another user's behalf; an authenticated user can only submit their own feedback. You can submit feedback even if Serval hasn't requested it. Submitting again updates the user's newest feedback entry on the ticket. Omitting the comment preserves an existing comment. The response contains the recorded feedback. Use `GET /v2/ticket-feedback` to list recorded feedback. Submissions also trigger **Ticket feedback submitted** workflows. *** ## Viewing feedback ### On individual tickets Feedback appears in the ticket detail view once submitted. The rating and timestamp are shown. ### Team analytics The analytics dashboard includes an AI Feedback chart when feedback is enabled for your team. It shows the overall positive feedback percentage and trends over time. *** ## Frequently asked questions With **Meaningful tickets**, only tickets with significant Serval interaction (2+ Serval messages, or 1 workflow run and 1 message) qualify. With **All tickets**, feedback is requested for every resolved ticket where your team collects Serval feedback, regardless of how much Serval was involved. Sampling below 100% and the once-per-ticket limit also apply. Not currently. The feedback request is standardized across all teams. Yes. Toggle off the feedback setting at any time. This stops new feedback requests but preserves existing feedback data. No. Feedback is purely for reporting and analytics. # Filter & Sort Tickets Source: https://docs.serval.com/sections/documentation/ticketing/manage-collaborate/filter-sort Find and organize tickets using filters, saved views, and sorting options Serval provides powerful filtering and sorting capabilities to help you find tickets and organize your queue. *** ## Filtering tickets ### Quick filters Use **Filter** in the view bar above the ticket list to narrow results by common attributes: Match a word or phrase in the ticket title Filter by To Do, In Progress, Done, or Canceled Show tickets assigned to specific team members Filter by owning group, including **My assignment groups** Filter by urgency level Find tickets with specific tags Show tickets approaching or past due Filter by creation or update date ### Filter operators Each filter supports operators that give you precise control over matching: | Operator | Available On | Example | | :- | :- | :- | | **is** | All attributes | Status is "In Progress" | | **is not** | All attributes | Assignee is not "Unassigned" | | **before** | Date fields | Created before January 1 | | **on or after** | Date fields | Updated on or after last Monday | | **contains** | Title | Title contains "offboarding" | | **does not contain** | Title | Title does not contain "test" | | **starts with** | Title | Title starts with "Offboarding:" | Operators vary by attribute type. Date fields support time-based operators, selection fields support equality operators, and the **Title** filter supports substring operators. You can also filter by any of your team's custom fields. Open **Filter** and type a field name to find it under the **Custom fields** group in the menu. On the **Created**, **Completed**, and **Last commented** filters, the **Custom range** option also accepts optional start and end times and an IANA time zone. Leave the times blank to keep a whole-day range, where the end date stays inclusive through the end of that day. ### Involves filter The **Involves** filter lets you find all tickets where a specific person is involved in any capacity: * Assignee * Requester * Commenter * Mentioned * Approver * Task assignee This is useful when you need to see every ticket a person has touched, regardless of their specific role on the ticket. ### Combining filters Apply multiple filters to narrow your results. Filters work together using logical AND: * **Status: In Progress** + **Assignee: Me** = Tickets I'm currently working on * **Priority: High** + **SLA: Overdue** = Urgent tickets that need immediate attention * **Involves: Me** + **Status: To Do** = All open tickets where I'm involved in any capacity Click the **X** on a filter chip to remove that filter. Click **Clear** to discard unsaved changes on the default view, or **Reset** to revert an edited saved view. *** ## Sorting tickets Change how tickets are ordered in your list view: | Sort option | Description | | :- | :- | | **Date created** (newest first) | Most recently created tickets at top | | **Date created** (oldest first) | Oldest tickets at top | | **Priority** | Highest priority tickets first | | **Date SLA breaches** | Tickets closest to SLA deadline first | | **Date updated** | Most recently modified tickets first | Click **Save view** to keep your sort, group, and display settings in a saved view. *** ## Saved views Create saved views to quickly access frequently used filter, sort, and display settings, including custom status or priority group order. ### Create a saved view Configure the filters you want to save. Click **Save view** in the view bar after you change filters or display settings. To change an existing saved view, click **Update**. To keep the original and save your changes, click **Save as new**. Give your view a descriptive name, such as "My Open Tickets" or "High Priority Bugs." Saved views appear as tabs in the view bar above the ticket list. When you save a view on a team's ticket list, the **Save to** picker lets you keep it personal, save it to the team, save it to a [visibility group](/sections/documentation/ticketing/manage-collaborate/visibility) you belong to, or save it to an [assignment group](/sections/documentation/ticketing/ticket-configuration/assignment-groups) (ticket sidebar group) you belong to. A view saved to a group is shared with every member of that group. Group ownership is fixed once saved: to move the view elsewhere, use **Save as new** to create a copy. ### Set a default view Choose the view a ticket list opens on. Open a view's menu in the view bar and select **Set as default**, or **Unset default** to clear it. The default view is marked with a pin icon, and a fresh tab or reload lands on it, while a view you select during a session takes over until you leave. Defaults are stored per surface, so each team's ticket list and your My Tickets list keep their own, and they follow you across devices. ### Example views **Filters:** Assignee = Me, Status ≠ Done Shows all tickets assigned to you that aren't completed. **Filters:** Assignee = None, Status = To Do Shows new tickets waiting to be picked up. **Filters:** SLA = Due Soon or Overdue Shows tickets that need attention to meet SLA commitments. **Filters:** Title contains "offboarding" Shows every ticket whose title mentions offboarding, whatever its type or status. **Filters:** Status = Done, Updated = This Week Shows tickets completed in the current week for reporting. *** ## Grouping tickets Group your ticket list by a property to organize tickets into sections. This is useful for organizing or reviewing tickets by a shared attribute. ### Available group-by options | Group by | Description | | :- | :- | | **Assignee** | Group tickets by who they're assigned to | | **Status** | Group tickets by their current workflow stage | | **Priority** | Group tickets by urgency level | | **Team** | Group tickets by responsible team | | **Created date** | Group tickets by when they were submitted | | **Updated date** | Group tickets by when they were last modified | | **Due date** | Group tickets by their due date | To group tickets, open **Display** above the list, choose **Group by**, and select a property. Tickets are organized into sections labeled by the property value. When grouped by **Status** or **Priority**, use **Sort status groups** (or **Sort priority groups**) in the same menu and drag sections into order. The order is saved with the current view. After you choose a **Group by**, the same **Display** menu offers **Sub-group by** a second property, splitting each group into labeled sub-groups (for example, group by **Assignee** and sub-group by **Status**). Choose **No sub-grouping** to turn it off. Like the group-by, the sub-grouping is saved with the view. Sub-grouping applies to team ticket lists and is ignored on the cross-team My Tickets list. Grouping works alongside filters and sorting. For example, filter by "Status: In Progress," group by "Assignee," and sort by "Priority." This shows each team member's active workload ranked by urgency. *** ## Ticket views ### List view The default view displays tickets as a list with key attributes visible: * Title and optional message preview on hover * Configurable columns such as status, priority, and assignee (choose columns in **Display**) * SLA status, labels, and timestamps when those columns are enabled * Your team's custom fields and per-policy SLA columns, toggled from the **Custom fields** and **SLAs** headings in the **Display** menu's column picker * An optional **Chat channel** column (off by default, team ticket lists only) that shows the Slack or Microsoft Teams channel a ticket came in on, or **Direct message** for a DM. Turn it on in **Display**. * On a team's ticket list, an optional **Visibility group** column showing which [visibility groups](/sections/documentation/ticketing/manage-collaborate/visibility) can see each ticket. Turn it on in **Display**. It isn't offered on the cross-team My Tickets list. * Click a ticket to open its detail pane beside the list Journey parent tickets and their tasks appear in team ticket lists by default for all teams. If your team prefers to keep them out of the list, open **Display** above the list and turn **Show journeys** off to hide journey content as a unit. Your My Tickets list offers the same **Show journeys** control in its **Display** menu. ### Board view Switch to board view to see tickets organized by status in a Kanban-style layout: * **Drag and drop** tickets between columns to update their status * Each column represents a workflow status for your team * **Update ticket properties** directly from cards. Change priority or assignee without opening the ticket * Board view is always grouped by status. **Group by** and status sort in **Display** aren't available in board view * Great for visualizing workflow and identifying bottlenecks Board view is especially useful during triage sessions. Drag incoming tickets from "To Do" to "In Progress" as you assign them, and update priority directly from the card. *** ## Search Use the search bar to find tickets by: * **Ticket title** - Match words in the ticket title * **Description** - Search within ticket descriptions * **Requester** - Search by who submitted the request * **Ticket ID** - Jump directly to a specific ticket * **External ticket ID, key, or number** - Enter a linked Jira key such as `IT-42` or a ServiceNow number such as `INC0010001`, `RITM0010001`, or `HRC0010001`. Partial numbers work too, and matching ignores capitalization. Combine search with filters for precise results. For example, search "password reset" with filter "Status: To Do" to find unresolved password requests. *** ## Archiving tickets Team managers can archive tickets to keep active queues clean and focused. * **Who can archive:** Team managers * **Which tickets:** Best practice is to archive tickets in a resolved state (Done or Canceled). Serval doesn't block archiving open tickets. * **What happens:** Archived tickets disappear from active views but they're still accessible in read-only mode * **How to find them:** Team managers can open **Settings** in the relevant team's sidebar, then **Archives → Tickets**. Other team members with archive viewing access can press **Command+K** (**Ctrl+K** on Windows), search for **archived tickets**, and select **Go to \[team name] archived tickets**. Archived tickets aren't shown through filters on the active ticket list. Archiving is non-destructive. Archived tickets retain all their data and history. They're simply hidden from default views. *** ## Moving tickets to another team Select tickets in the list, then use **Move to team** in the bulk-selection bar to move up to 100 of them to another team at once, instead of one at a time from each ticket's menu. * **Who can move:** Anyone with edit access on the source team. * **Which tickets:** The selection must come from a single team. You're warned before moving tickets into a team you don't belong to. * **What happens:** Each ticket adopts the destination team's configuration, including its statuses, priorities, SLAs, and [channel syncing](/sections/documentation/ticketing/ticket-configuration/syncing). *** ## Best practices Use saved views like "My Tickets" or "SLA At Risk" to prioritize your work Switch to board view when organizing incoming tickets to quickly assign and prioritize Check the SLA filter throughout the day to catch tickets before they breach Set up shared views for common team needs like "Unassigned" or "Escalated" # Notifications Source: https://docs.serval.com/sections/documentation/ticketing/manage-collaborate/notifications Configure alerts and stay informed about ticket updates Stay on top of your tickets with notifications for assignments, mentions, replies, and workflow updates. Configure notifications to match how you work. *** ## Notification Types Serval sends notifications for key events: When you are assigned to a ticket When you are mentioned in a ticket or comment When someone replies to a ticket When a workflow run is approved When a workflow run is rejected When a suggestion set is created When an access request is approved When an access request is rejected Adding an [internal note](/sections/documentation/ticketing/resolving-tickets) to a ticket sends the ticket's assignee a **New Ticket Reply** notification. Only the assignee is notified — the requester and other subscribers are not, since internal notes stay private to your team. Because notes never sync into a connected external thread, the assignee is notified even on externally connected (for example, Slack) tickets. *** ## Notification Channels Receive notifications where you work: ### Slack Notifications appear as direct messages from Serval: * Receive notifications for configured events * Assignment, reply, and mention DMs show the ticket title on the card, so you can see which ticket a message is about * Click through to open tickets in Serval ### Email Receive email notifications for ticket activity: * Individual emails for important events * Click links to jump directly to tickets in Serval *** ## Assignment Notification Settings Ticket assignment notifications can be configured at three levels: 1. **Personal** — Each user controls their own assignment notification preferences 2. **Team** — Team managers set default assignment notification behavior for the team 3. **Org-wide** — Organization admins configure default assignment notifications across all teams At each level, you can choose the delivery channel: * **Slack** — Receive assignment notifications as Slack DMs * **Email** — Receive assignment notifications via email * **Both** — Receive on both channels Personal settings override team defaults, which override org-wide defaults. *** ## Configuring Notifications Serval uses a two-level notification system: team-wide defaults and individual user preferences. ### Team Default Notification Settings Admins configure default notification preferences for the entire team. These defaults apply to all team members unless they create personal overrides. Go to **Settings** → **Notifications**. Toggle which events trigger Slack notifications: * **Workflow Run Approved** — When a workflow run is approved * **Workflow Run Rejected** — When a workflow run is rejected * **New Ticket Reply** — When someone replies to a ticket * **User Mention** — When you are mentioned in a ticket or comment * **Suggestion Set Created** — When a suggestion set is created * **Ticket Assigned** — When you are assigned to a ticket * **Access Request Approved** — When an access request is approved * **Access Request Rejected** — When an access request is rejected Choose which events also send email notifications. Most teams enable fewer email notifications than Slack to reduce inbox noise. Click **Save** to apply these defaults to all team members. Users can override these team defaults in their personal settings. Changes to team defaults do not affect users who have created personal overrides. *** ## Personal Notification Preferences Users can customize their own notification preferences to override team defaults. ### Update Your Personal Settings Click your **name** in the sidebar to open your profile, then select the **Notifications** tab. Toggle notification types on or off for both Slack and Email channels. Your personal preferences will take precedence over team defaults. Click **Save** to apply your personal notification settings. Changes take effect immediately. Test by having a teammate assign you a ticket or mention you to confirm your settings work as expected. *** ## Admin: Managing Specific User Notifications Admins can view and manage notification settings for individual users when troubleshooting or setting up new team members. ### View or Update a User's Notifications In the **Organization** workspace, open **Settings → Users**. Find and click on the user you want to manage. Click the **Notifications** tab to view their current settings. Update which notification types and channels apply to this user. Click **Save** to apply the updated settings. When admins update a user's notification settings, those changes override team defaults. Users can still modify their own settings afterward. ### When to Manage User Notifications * **Onboarding** — Verify new team members have appropriate notification settings * **Role changes** — Update notifications when someone changes teams or responsibilities * **Troubleshooting** — Help users who report missing or excessive notifications * **Coverage** — Temporarily enable notifications for backup coverage during PTO *** ## Best Practices Start with essential notifications (assignments, mentions) and add more only if needed. Too many notifications leads to alert fatigue. Configure Slack notifications for time-sensitive items like assignments and workflow approvals. Use email for less urgent updates. *** ## Troubleshooting * Ensure Serval app is installed in your Slack workspace * Check that you haven't muted the Serval DM * Verify Slack notifications are enabled in Serval settings * Confirm the specific event type is enabled in your notification preferences * Review and disable notification types you don't need in your settings * Consider enabling fewer events for Email vs Slack * Adjust team default settings if the entire team is over-notified * Check your spam/junk folder for Serval emails * Verify Email notifications are enabled in your settings * Confirm your email address is correct in your user profile # Updating Ticket Properties Source: https://docs.serval.com/sections/documentation/ticketing/manage-collaborate/update-ticket-properties Keep tickets organized by updating status, priority, assignee, and labels Keep tickets organized by updating properties as you work. Update from the ticket list, the detail view **Properties** panel or header pills, or by asking Serval in the conversation. *** ## From list view Click the property control in the row to update without opening the ticket: Move tickets between workflow stages Status dropdown Adjust urgency level Priority dropdown Reassign to a team member Assignee dropdown Add or remove labels. In narrow or sidebar list layouts, labels are display-only. Edit them from the ticket detail view. Labels dropdown Updating from list view is the fastest way to triage multiple tickets quickly. In board view, drag tickets between columns to change status. *** ## From detail view Open a ticket and update properties from the **Properties** panel on the right, or from the property pills in the page header when the panel is closed: * Click any property to open its menu. Changes save automatically. * Set **Assignment group** to choose the ticket's owning [assignment group](/sections/documentation/ticketing/ticket-configuration/assignment-groups). This is separate from the individual assignee. * Set **Team** to move the ticket to another team. Serval asks you to confirm the move first, then links you to the moved ticket when you're a member of the new team. The ticket adopts the destination team's configuration, including [channel syncing](/sections/documentation/ticketing/ticket-configuration/syncing). * On smaller screens, use **Open properties** for the full panel. * Changes appear in the **Activity** timeline in the conversation. *** ## Reclassify a ticket If a ticket was classified incorrectly, open its action menu and select **Reclassify as Incident** or **Reclassify as Request**. This action is available to ticket-editing agents and managers with the **Reclassify ticket type** permission. Archived and trashed tickets can't be reclassified. Serval uses AI to adapt the ticket's title, description, priority, labels, category, and custom-field values to the destination type. Custom-field values without a corresponding destination field remain saved but aren't shown on the reclassified ticket. If you return to a previous type, AI maps the current values again. Previously saved destination values stay unless the mapping updates them. Only fields allowed by the destination type's current settings and your permissions are displayed. Serval maps the ticket's current status to a corresponding status in the destination type's same progress group: Todo, In Progress, Done, or Canceled. Mapping runs every time you reclassify, so work completed between reclassifications determines the next status. Reclassification preserves the completion time, ticket identity, conversation, assignment, relationships, and SLA history. Linked external records keep their existing types. After reclassification, a notification confirms the new type, and the ticket refreshes to show its mapped properties and custom fields. If mapping fails or the ticket changes during reclassification, retry from the action menu. Manual reclassification remains available when automatic status inference is turned off. ## From chat Use natural language or @ mentions directly in the ticket conversation: **Change status:** * "Mark as resolved" * "Set status to in progress" **Reassign:** * "Assign this to @sarah" * "@john can you take this?" **Set priority:** * "Set priority to high" * "This is urgent" **Add labels:** * "Add the billing label" Using @ mention to reassign Serval understands natural language, so you don't need to use exact commands. Just describe what you want to change. *** ## Quick reference ✓ = visible in that surface; — = not shown. In **Chat**, changes appear in the **Activity** timeline. | Property | List View | Detail View | Chat | | :- | :- | :- | :- | | Status | ✓ | ✓ | ✓ | | Priority | ✓ | ✓ | ✓ | | Assignee | ✓ | ✓ | ✓ (@ mention) | | Assignment group | — | ✓ | — | | Labels | ✓ | ✓ | ✓ | | Due Date | ✓ | ✓ | — | | SLA | — | ✓ | — | | Ticket Type | — | ✓ | — | | Team | — | ✓ | ✓ | *** ## Related Learn about all ticket properties Guide to working through tickets # Visibility groups Source: https://docs.serval.com/sections/documentation/ticketing/manage-collaborate/visibility Restrict who can see a set of tickets If you have tickets that may contain sensitive information, use visibility groups to restrict who can see a set of tickets. You can configure visibility groups to populate automatically from a filter, manually, or both. Tickets within a visibility group are not generally visible. They are visible to members of the group, and to anyone who normally has access (e.g. assignee, requester). When you save a visibility group, Serval rechecks every existing ticket on the team against it in the background, so matching tickets join and tickets that no longer match leave. New and updated tickets are checked as they change. Tickets added to a group manually stay until someone removes them. *** ## Filter tickets by visibility group On your team's ticket list, open **Visibility group** and select one or more groups. The list shows tickets that belong to any selected group and that you have access to. Select a group again to remove it, or select **All tickets (no group)** to clear the selection. Your selection stays in the page URL so you can reload or share it. A view saved to a visibility group always shows that group's tickets, so its visibility-group selector is locked. If you manage a selected group but aren't a member, you'll see its membership panel before the ticket list. Join each selected group you aren't a member of to view the combined results, or choose **Back to all tickets** to clear the selection. ## Adding a visibility group Managers of a team can create visibility groups, configure group settings, and add members who can view tickets within the group. To create a visibility group: 1. Go to **Settings -> Ticketing -> Ticket Visibility**. 2. Click **+ Visibility group** in the top right. 3. Give the group a name, and optionally a description. 4. Select how tickets join the group: * **Added manually** — a manager adds tickets one at a time or in bulk. * **Matched by a filter** — the group covers tickets matching the filter you specify. Conditions can match ticket properties (including your team's custom ticket types), the ticket's assignment group (available once the team has assignment groups configured), the requester's built-in fields (Department, Job title, Email, Timezone, and Locale), and requester custom fields. Filter conditions can be combined with more than one connector. Conditions joined by **AND** must all match, and switching a connector to **OR** starts a new alternative group. A ticket matches the filter when it satisfies any one group. * **All tickets on this team** — the group sees every ticket on the team, including ones more specific groups also cover. * **Tickets no other group covers** — the group covers a ticket only while no other group does. See [Fallback visibility](#fallback-visibility). 5. Add members to the group. *** ## Fallback visibility A fallback group covers the tickets no other visibility group covers, so uncategorized work has an owner. Unlike **All tickets on this team**, its members see only the leftovers: as soon as another group covers a ticket, the fallback stops covering it, and if that group later stops, the fallback takes it back. Each team can have one fallback group. You can set it from the group's own settings, or from the **Fallback visibility** card at the bottom of the Ticket Visibility page. A group can be the fallback only if nothing else decides its membership — it can't also have a filter or cover all tickets. Setting a fallback changes who can see tickets across the whole team. Today, a ticket in no visibility group is visible to everyone on the team. Once a fallback covers the leftovers, every ticket belongs to a group — so people who aren't in any group will only see tickets they requested, are assigned, are subscribed to, or were mentioned in. As with filter-based groups, saving a fallback rechecks the team's existing tickets, and new or updated tickets are checked as they change. # Ticketing Overview Source: https://docs.serval.com/sections/documentation/ticketing/overview Resolve employee requests with AI-powered ticketing across Slack, Teams, email, and web Serval's ticketing system brings all employee requests into one place — whether they come from Slack, Teams, email, or web. Serval automatically triages, routes, and resolves routine requests so your team can focus on the work that matters. ## Why Serval Ticketing * **Unified inbox** - Manage requests from any source — Slack, Teams, email, and other input portals — in one place * **AI-powered triage** - Serval automatically categorizes, prioritizes, and routes tickets * **Automatic resolution** - The help desk agent routes requests to the right automation to resolve them without human intervention * **Smart escalation** - Complex issues are surfaced to the right team member with full context * **Flexible views** - Switch between list and board layouts to match how your team works * **External sync** - [Sync with your existing ticketing system](/sections/documentation/ticketing/ticket-configuration/syncing) to keep both platforms in sync *** ## Ticket Types Serval supports five ticket types: Fulfillment work like access, equipment, and service requests Service issues where normal operation must be restored A high-impact incident, such as a widespread outage, that needs a coordinated response A controlled modification to your environment that follows a governed lifecycle A root-cause investigation behind one or more incidents, tracked to a resolution For incident tickets, Serval can identify related incoming tickets, link them to the incident, notify users that a related incident exists, and surface incident context in the conversation. Learn how the ticket types differ and how AI classifies them Triage, route, automate, and resolve incidents in Serval Track changes through a governed lifecycle with approvals and automations Investigate root cause, coordinate the fix, and prevent recurrence with AI *** ## Getting Started Get up and running with Serval ticketing in minutes Guide to working through tickets from first response to resolution *** ## Manage & Collaborate Tools for support teams to manage tickets and work together effectively. Change status, priority, assignee, and labels Find tickets with filters, saved views, and search Collect and manage feedback from requesters Configure alerts for assignments, updates, and SLAs *** ## Ticket Configuration Configure how tickets are categorized, prioritized, and routed. Understand ticket anatomy, properties, and all configuration options Requests, incidents, changes, and problems Incident triage, handling, and external sync behavior Governed change lifecycle with approvals and automations Root-cause investigation, problem tasks, and AI remediation Custom workflow stages Urgency levels Response & resolution times AI-inferred ticket content classification Configure assignment rules for automatic ticket assignment Custom tags Structured key-value data on tickets Break tickets into sub-items Connect to your existing ticketing system *** ## Reporting & Insights Track performance and identify trends. Track ticket metrics, team performance, and support trends *** ## For Employees Employees can submit and track their own requests through any connected channel. How to create tickets and get help from support teams View status updates and manage submitted requests *** ## Next Steps New to Serval ticketing? Start with the [Quickstart guide](/sections/documentation/ticketing/quickstart) to get your team set up, or explore [The Serval Ticket](/sections/documentation/ticketing/ticket-configuration/serval-ticket) to understand ticket configuration. # Problem Management Source: https://docs.serval.com/sections/documentation/ticketing/problem-management Investigate recurring issues or cause of incidents, and use AI to remediate and prevent future disruption Problem management in Serval is how you find and eliminate the underlying cause behind one or more incidents. Where an incident requires restoring service quickly, a **Problem** ticket tracks the investigation, root-cause analysis, and permanent fix so the same issue doesn't come back. Serval pairs the ITIL problem workflow with AI that suggests remediations, runs root-cause analysis, and proactively surfaces problems before they turn into incidents. *** ## What a problem ticket is A **Problem** ticket is a ticket type dedicated for investigating the cause behind recurring or high-impact incidents and driving it to a permanent resolution. Unlike requests (which fulfill an ask) or incidents (which restore service), problem tickets exist to answer *why* something keeps happening. They capture the investigation, the impacted services, a workaround, and the eventual fix in one tracked record. Incidents are about restoring service quickly. Problems are about making sure the same issue doesn't come back. A single problem often sits behind several related incidents. *** ## When to use a problem ticket Use a **Problem** ticket to capture the underlying issue itself, a statement of what's going wrong and its suspected cause, so it can be tracked to a resolution while service is being restored. Common examples include: * **Recurring issue**: "The VPN keeps dropping every afternoon around peak usage" * **Unexplained outage**: "Last week's AWS outage was caused by an unknown issue that appears related to the database" * **Known error**: "Large report exports time out; the workaround is to split them, but the underlying cause is still open" An owner is assigned the problem and decides what to do with it: whether to trigger a [Change](/sections/documentation/ticketing/change-management) to implement the permanent fix or raise a [Request](/sections/documentation/ticketing/ticket-configuration/ticket-types#requests) for a related service need. *** ## Creating a problem ticket Problem tickets are created the same way as every other ticket type in Serval. There's nothing inherently different about a problem. What varies is *who* opens it: * **Manually**: A team member opens a problem directly, or spins one up from an incident or major incident that revealed a deeper issue. * **By a background agent**: A [background agent](/sections/documentation/catalyst/agents) that has proactively identified a problem and been instructed to create one opens the ticket on its own. When a background agent creates a problem, the ticket links back to the [agent report](/sections/documentation/catalyst/agents) that generated it. You can then review the full root-cause analysis behind the problem. Click **Create Ticket** from the ticket list, or open a problem from an existing ticket. In the dialog header, select **Problem** as the ticket type. From an incident or major incident, choose **Derive ticket…** to create a problem. Serval uses AI to draft the new problem's title, description, priority, labels, and custom fields from the source ticket, and links the two records automatically. See [Ticket Flows](/sections/documentation/ticketing/ticket-flows) for the full behavior. Provide a title and description. You can also set priority, assignee, assignment group, category and subcategory, labels, due date, and any custom fields configured for problems. Attach the configuration items and services the problem affects so the team can track impact and route the work correctly. The ticket is created and the investigation begins. You can link related incidents so the problem tracks everything it sits behind. *** ## How problem management works in Serval A team member opens a problem, derives it from a recurring incident or major incident, or an AI background agent surfaces it from issues discovered across your environment. When a problem is derived from another ticket, key fields carry over and the tickets are linked. When a background agent creates it, the problem links back to the agent report and its root-cause analysis. Your team sets priority, category, and ownership (assigning an assignment group and an assignee), and links any related incidents the problem represents. The owner investigates across systems, logging findings as internal notes. Problem tasks break the investigation into assignable pieces of work, and AI assistance helps troubleshoot and record what it finds. Serval suggests remediations: a knowledge article, a missing workflow or automation, or the skills the Help Desk Agent needs. When a permanent fix requires a controlled modification, a [Change](/sections/documentation/ticketing/change-management) is triggered, subject to your approval policies. Once the root cause is eliminated, the problem is resolved. Notifications and updates flow to linked records and stakeholders so everyone affected by the original incidents is informed. *** ## AI-powered problem management Serval's AI is embedded throughout the problem lifecycle. Build and run workflow automations inside problem tickets by describing what you want in plain language, with AI assistance throughout the building experience. AI proposes auto-remediations and fixes: a new or updated knowledge article, a missing workflow or automation, or the skills the Help Desk Agent needs to resolve or prevent the issue. The Catalyst assistant interacts with the problem ticket, logs new information as it's discovered, troubleshoots across connected systems, and helps manage the state of the record. Background agents run root-cause analysis and proactively discover problems from incident patterns, generating automations to anticipate issues before they occur. Suggested remediations are surfaced for review on the record. You decide what to accept, turning a suggestion into a knowledge article, a workflow, or an added agent skill. *** ## Problem tasks Problems are worked through **[problem tasks](/sections/documentation/ticketing/ticket-configuration/tasks)**: assignable units of investigation or remediation. * **Workflow automation**: The Help Desk Agent will call any available workflows to either investigate or remediate the issue. This includes an update in an external system or in Serval. * **AI assisted troubleshooting**: Catalyst assistant helps with problem discovery and resolution, and automatically generates remediations. * **Manual creation**: Team members can create problem tasks by hand, each with its own assignment group allocation. Tasks can be routed to the group best suited to the work, and SLAs can be applied to individual tasks and to the parent problem. *** ## Assignment and ownership Problems and problem tasks support both manual and automated allocation: * **Manual allocation**: Assign a problem to an assignment group and an individual assignee by hand. * **Automatic allocation**: Set the assignment group automatically, driven by an [assignment rules](/sections/documentation/ticketing/ticket-configuration/assignment) table or a workflow. *** ## Categorization and impact * **Category & subcategory**: Classify each problem record for routing, reporting, and analysis. * **Configuration item & service association**: Associate the problem with the [CIs](/sections/documentation/databases/overview) and services it relates to. * **Impacted service detection**: Serval automatically detects and lists the services a problem impacts. *** ## Linking and related records Problems rarely stand alone. Serval connects them to the rest of your ITSM records: * **Link to any record**: Link a problem to any existing ticket record, such as a change or an incident. * **Create from any record**: Create a problem from any ticket record (change, incident, and more), pre-populating key fields from the source. This keeps every incident a problem sits behind, and every change that resolves it, connected to a single investigation. *** ## Approvals, SLAs, and notifications * **Rules-based change approval**: Table-driven approval policies govern when a change stemming from a problem requires authorization. * **SLAs**: Apply SLA records to both problem and problem task records to track investigation and remediation time. * **Notifications**: Generate notifications on relevant problem record updates so owners and stakeholders stay informed. *** ## Audit and traceability * **Internal notes**: Add and view previously entered notes that are hidden from end users, keeping the investigation trail private to your team. * **Audit traceability**: Every record change is traceable, showing who changed what and when. *** ## Related pages * [Ticket Types](/sections/documentation/ticketing/ticket-configuration/ticket-types) * [Ticket Flows](/sections/documentation/ticketing/ticket-flows) * [Incident Management](/sections/documentation/ticketing/incident-management) * [Change Management](/sections/documentation/ticketing/change-management) * [Tasks](/sections/documentation/ticketing/ticket-configuration/tasks) * [SLAs](/sections/documentation/ticketing/ticket-configuration/slas) * [Workflows](/sections/documentation/workflows/overview) # Ticketing Quickstart Source: https://docs.serval.com/sections/documentation/ticketing/quickstart Get up and running with Serval ticketing in minutes Get your team set up to receive, manage, and resolve tickets with Serval's AI-powered ticketing system. *** ## Prerequisites Before you begin, ensure you have: * Ticket management permissions in at least one team * A connected channel for receiving tickets *** ## Quick Setup Set up where tickets come from. Connect your input channels so employees can reach your team. Configure your intake channels Submit a test request through your connected channel to see how Serval handles it: 1. Send a message through your connected channel 2. Watch the ticket appear in your Serval inbox 3. Review how Serval categorizes and responds to the request Learn how to interact with the ticket to best resolve it Try different types of requests (questions, access requests, issues) to see how Serval triages each one. Customize how tickets are categorized, prioritized, and assigned based on what you learned from testing. Configure ticket based on your needs The real power of Serval is resolving requests automatically. Add workflows, Skills, and access policies so Serval can handle requests end to end without human intervention. Build automations that resolve requests automatically Give Serval runbooks and instructions for handling specific situations Automate access requests to any role in any application Start with the requests your team handles most frequently. Even a few automations can significantly reduce manual work. If your team uses an external ticketing system, connect it to keep both systems in sync. Connect to your existing ticketing system Configure how your team views and stays informed about tickets. Create saved views for your workflow Configure alerts for assignments and SLAs Once tickets are flowing, use analytics to track performance and identify improvements. Track ticket metrics and team performance *** ## Create a ticket in the web app In the **Create Ticket** dialog, enter a title and describe the request. **Let Serval respond** is on by default for eligible ticket types. Serval receives your description as the first request message and responds to it. Turn the switch off to create the ticket without an AI response. The switch and assignee labels use your configured assistant name. If you have permission to set the requester or assign tickets, **People** groups those controls and the switch. You can choose a human assignee or assignment group while Serval stays active. Choose **Auto Assign** to apply your team’s assignment rules. If no people controls are available, the switch appears on its own without a **People** section. Use the actions at the bottom to add context: * **Add files**: Attach supporting files to the ticket. * **Add items**: Link affected assets or configuration items when creating a Change ticket. Serval handling requires a description. The switch isn't available for Change, Problem, or Major Incident tickets, which require human ownership. Your choice persists when you switch ticket types within the dialog; opening a new dialog restores the default. To create a ticket from an existing ticket, choose **Select a ticket** beside **from ticket** in the header. This option appears when you have permission and the selected ticket type supports it. ## Next Steps Understand ticket properties and the detail view Learn how to update, respond, and use Co-pilot # Resolving Tickets Source: https://docs.serval.com/sections/documentation/ticketing/resolving-tickets A guide to working through tickets from first response to resolution This guide walks through the process of resolving tickets in Serval, from finding open tickets to closing them out. *** ## Finding open tickets Start by locating tickets that need your attention. ### In the web interface 1. Navigate to **Tickets** in the sidebar 2. Use the **"Involves"** filter to find tickets assigned to you 3. Filter by status (for example, "Open" or "In Progress") to see active tickets The "Involves" filter shows all tickets where you're the assignee, requester, commenter, mentioned, approver, or task assignee. Use it to find everything you're connected to. ### In Team Inbox channels If your team has configured a Team Inbox channel in Slack, tickets assigned to your team will automatically appear as threads in that channel. This provides a centralized place to triage tickets without switching to the web interface. Team Inbox channels are private Slack channels where all escalated tickets for your team appear. See [Configure Team Inbox Channels](/sections/integrations/slack#configure-team-inbox-channels) for setup instructions. *** ## Ways to resolve tickets There are a few ways to resolve tickets in Serval. Choose the method that best fits the situation. ### 1. Manually resolve Respond directly to the requester with answers, updates, or follow-up questions. Communicate with the requester and your team in the **Activity** thread. Forwarded messages (for example, from Slack) show a **Forwarded message from** line below the quoted content. #### Public response Visible to the requester. Use for: * Answering questions * Requesting more information * Providing updates * Confirming resolution #### Internal note Only visible to team members. Use for: * Documenting investigation steps * Sharing context with teammates * Handoff information when reassigning * Notes that shouldn't be shared with the requester Internal note toggle Click the sticky-note icon in the chat to switch to an internal note before typing. #### Translate the conversation When a ticket comes in a language you don't read, translate it into your own interface language without leaving the ticket. * **A single message:** Open the message's actions menu and choose **Translate**. The translated text replaces the message, with a status label above it (**Translating...**, then **Translated**). Below the message, a **Show original** link reveals the untranslated source, and **Hide original** collapses it again. * **The whole thread:** Click the **Translate thread** (languages) icon in the **Activity** bar to translate every eligible message at once. If some messages couldn't be translated, the control offers **Retry thread translation**. Translation targets whatever language the Serval interface is set to for you, so two teammates viewing the same ticket can each read it in their own language. It's available to team members with permission to translate tickets, which the Read-Only Agent role and above include. #### Messages from personal conversations If your organization uses the personal help desk in Microsoft Teams, messages it forwards to a ticket keep the Microsoft Teams source indicator. This applies to the opening request and later forwarded replies. When a forwarded message differs from the requester's words, expand **Original requester message** below it to read the original text, with their name and timestamp. If the request combines multiple messages, the section lists them in order. **Original requester excerpt** means only the part shared with your team appears. Click the original message's timestamp to switch between the date and time and how long ago it arrived. The ticket's other timestamps follow the same setting. Messages copied without changes don't repeat the same text. If someone later edits the ticket message, you can still expand the original. Older forwarded messages may show **Original messages are unavailable.** Closing the personal conversation keeps the ticket's provenance and shared originals. Deleting that conversation removes them from the ticket. The original-message section shows the text shared with your team; it doesn't open the requester's private conversation. ### 2. Run existing help desk workflows Automate actions directly from a ticket using organization-wide workflows. 1. In the reply chat, type `/` or select **Trigger a workflow** (the `/` button). The button opens the workflow menu at the end of your draft, including after a mention or image. 2. Select from available Help Desk workflows 3. Fill in any required inputs 4. Execute the workflow Slash command to trigger workflow Workflow progress and results appear in the **Activity** timeline. Help Desk workflows are available to all users in your team and are designed for common support scenarios like password resets, software access requests, and IT troubleshooting. ### AI agent after escalation When a ticket is escalated to a human agent, Serval's AI agent can remain active on the ticket. The AI continues to provide guidance, suggest knowledge base articles, and assist with resolution even while a human is working the ticket. This is configurable per team in **Team Settings**. ### 3. Open Copilot to run team-only workflows Use Copilot to access team-only workflows and get AI assistance for resolving tickets. Copilot uses context from your connected identity providers to enrich responses. It can retrieve a user's department, job title, manager, and other organizational details automatically so you spend less time looking up user information. Copilot is your AI assistant for resolving tickets faster. Click **Open Copilot** above the reply chat to: * Run team-only workflows that aren't available through the `/` command * Draft responses based on ticket context and your knowledge base * Summarize long ticket threads * Find information in your Skills and knowledge base * Get suggestions for next steps or escalation paths ### How to use Copilot 1. Open a ticket 2. Click **Open Copilot** above the reply chat 3. Ask what you need: * "Run the employee offboarding workflow for [john@company.com](mailto:john@company.com)" * "Draft a response explaining our refund policy" * "Summarize this ticket" * "What workflows can help with this?" * "Find a Skill about password resets" 4. Review and edit the response 5. Send or use the suggestion Team-only workflows are restricted to team members and are ideal for internal operations, sensitive data handling, and administrative tasks. They don't appear in the standard `/` workflow menu but can be accessed through Copilot. Copilot uses your team's skills and knowledge base. The more skills you add, the better Copilot performs. *** ## Close tickets When the requester's issue is resolved: 1. Send a final response confirming resolution 2. Update status to a "Done" status (for example, Resolved or Completed) - see [Updating Ticket Properties](/sections/documentation/ticketing/manage-collaborate/update-ticket-properties) for how to change status 3. The requester may receive a feedback request Include a brief summary of what was done in your closing response. This helps if the ticket needs to be referenced later. *** ## Delete archived tickets If you have permission to delete tickets in the team, you can delete them directly from the archive: 1. Open the team's **Settings** and select **Archives**. 2. On the **Tickets** tab, select up to 100 tickets. 3. Select **Delete** in the selection toolbar. 4. Review the confirmation, including any child tickets, and confirm **Delete**. Deleted tickets move to **Recently Deleted**. You can select **Undo** in the confirmation notification to restore them. A team can turn ticket deletion off entirely. In the team's **Settings**, open **Recently Deleted** and switch the **Ticket Deletion** toggle off (this requires permission to manage team settings). While deletion is off, the delete controls are unavailable and no tickets can be moved to Recently Deleted. Turning it back on resumes the automatic cleanup of tickets already in Recently Deleted. *** ## Quick reference | Action | How To | | :- | :- | | Find your tickets | Use "Involves" filter in Tickets view | | Send public response | Type a message and send (default) | | Add internal note | Click the sticky-note icon in the chat | | Run Help Desk workflow | Type `/` in the chat or click **/** in the toolbar | | Use Copilot | Click **Open Copilot** above the chat | | Run team-only workflow | Open Copilot and request the workflow | | Close ticket | Update status to Done | *** ## Related Change status, priority, assignee, and labels Learn about all ticket properties and views Learn about team-only and organization-wide workflows Configure Team Inbox channels in Slack # Assignment Rules Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/assignment Automatically route and assign tickets based on category, priority, status, and schedule Assignment rules let you define conditions that automatically determine what happens when a ticket is escalated to a human agent. Rules can match on [categories](/sections/documentation/ticketing/ticket-configuration/categories), [priorities](/sections/documentation/ticketing/ticket-configuration/priorities), [statuses](/sections/documentation/ticketing/ticket-configuration/statuses), [schedules](/sections/documentation/ticketing/ticket-configuration/schedules), requester group membership, and requester attributes, then assign tickets to specific users or an [assignment group](/sections/documentation/ticketing/ticket-configuration/assignment-groups). *** ## How Assignment Rules Work When a ticket is escalated from Serval AI to a human agent, the assignment process follows this order: 1. **Assignment rules** — Serval evaluates the ticket against your configured rules in order. The first matching rule (top of the list) determines the assignee. Drag rules to reorder them and change which one wins when multiple rules match. 2. **Default assignment** — If no assignment rules match, the ticket is assigned to your default group (if configured). 3. **[Skills](/sections/documentation/skills/overview)** — Natural language instructions for how Serval should handle assignment. 4. **Unassigned** — If nothing above applies, the ticket remains unassigned until manually claimed. *** ## Conditions Each assignment rule has one or more conditions that determine when it applies. All conditions on a rule must match for the rule to trigger. | Condition | Description | | - | - | | **Category** | Matches when a ticket has a specific [category](/sections/documentation/ticketing/ticket-configuration/categories). Serval AI infers the category from ticket content. | | **Priority** | Matches when a ticket has a specific [priority](/sections/documentation/ticketing/ticket-configuration/priorities) level (e.g. urgent, high, medium, low). | | **Ticket type** | Matches a built-in ticket type or a specific change or custom ticket subtype configured under **Team Settings → Ticket Types**. Draft, published, and deprecated models appear in the dropdown, so you can configure rules before publishing a model. | | **Status** | Matches when a ticket has a specific [status](/sections/documentation/ticketing/ticket-configuration/statuses). | | **Schedule** | Matches when the ticket escalation time falls within a configured business hours [schedule](/sections/documentation/ticketing/ticket-configuration/schedules). Useful for routing differently during and outside of working hours. | | **Requester group** | Matches when the ticket requester is a member of a specific group. Useful for routing a department's or region's requesters to a dedicated agent or group. | | **Requester's field** | Matches on an attribute of the ticket requester, such as their department, job title, email, timezone, or locale, or a user custom field where enabled. Type a value for text fields, including department. For custom fields with predefined options, select the values to match from a menu. | Most conditions can match on **is** or **is not**, so you can route on the absence of a value, such as *Priority is not Low* or escalations that land *outside* a business-hours schedule. The **Requester group** condition matches on membership only, with no *is not* variant. Combine multiple conditions to create precise rules. For example, you can route urgent billing tickets to a senior finance group during business hours, and to an on-call group outside of hours. *** ## Actions When an assignment rule's conditions match, Serval assigns the ticket based on your configured users and groups. ### Assign to users or groups Directly assign the ticket to specific users, or to one [assignment group](/sections/documentation/ticketing/ticket-configuration/assignment-groups). * **Users** — When multiple users are selected, they form a single pool and Serval picks one assignee. * **Group** — The ticket's owning group is set to that group. How (or whether) an individual member is chosen depends on the team's [Group member assignment](/sections/documentation/ticketing/ticket-configuration/assignment-groups#set-up-assignment-groups-for-a-team) setting (**Round-robin** or **Human triage**). A single rule can target either one group or one or more users — not both. ### Requester exclusion When evaluating candidates from assignment rules or default assignment, Serval automatically excludes the ticket's requester from the pool. This prevents a ticket from being auto-assigned back to the person who submitted it after escalation. If every candidate in the pool is the requester (for example, a default assignment group with only one member who is also the requester), the ticket is left unassigned. You can always [manually assign](/sections/documentation/ticketing/manage-collaborate/update-ticket-properties) a ticket to its requester if needed. Requester exclusion only applies to automatic assignment. ## Default Assignment In **Team Settings → Assignment → Assignment rules**, every team has a default assignment setting that acts as a fallback when no assignment rules match: * **Unassigned**: Tickets remain unassigned until someone manually claims them. * **Default group**: Tickets are automatically assigned to a specific group. * **Single user**: Tickets are automatically assigned to one specific user. Even when using assignment rules, set a default assignment group to catch tickets that don't match any rule. *** ## Creating an Assignment Rule Go to **Team Settings** → **Assignment** → **Assignment rules**. Click **Add Rule** to open the rule builder. Add one or more conditions. Choose the condition type (category, priority, ticket type, status, schedule, requester group, or requester's field) and select the matching value. All conditions must be true for the rule to trigger. Select **Assign to users/groups**, then choose the users or groups that should receive matching tickets. Click **Save** to activate the rule. *** ## Managing Rules Rules start collapsed so you can scan their order and destinations. Select a rule's condition summary to expand or collapse its details. A **+N** badge indicates additional conditions or actions. Use **Expand all** or **Collapse all** above the list to review several rules at once. The three-dot menu remains available while a rule is collapsed. Select **Add Rule** in the **Assignment flow** header to add another rule. The **Fallback assignment** card below the rules handles requests that do not match a rule. Open the **Settings** tab to manage assignment groups and their work schedules, the custom escalation workflow, and assignment preferences. ### Editing a Rule Open the three-dot menu on a rule card and select **Edit routing rule** to modify its conditions or actions. ### Reordering Rules Hover over the number inside a rule card to reveal its drag handle, then grab the handle to drag it up or down. Rules are evaluated top to bottom, so the rule closest to the top wins when more than one rule matches a ticket. Use this to set precedence when rules overlap, for example a "during business hours" rule above an "outside business hours" rule when their schedules touch. ### Deleting a Rule Open the three-dot menu on a rule card and select **Remove routing rule**. A confirmation prompt appears before the rule and all its conditions and actions are removed. *** ## Simulate assignment Use **Simulate** on **Team Settings → Assignment** to preview which rule would match a ticket — without changing any real tickets or assignees. The **Assignment Simulation** panel walks the same rule order as live escalation: first match wins, otherwise the ticket falls through to default assignment. Go to **Team Settings → Assignment** and click **Simulate**. Pick one mode: | Mode | Use when | | - | - | | **Request message** | You want to paste or type sample ticket text (for example, "VPN won't connect from home"). | | **Historical ticket** | You want to re-run rules against an existing escalated ticket on the team. | For a free-text request, set: * **Date and time** plus **timezone** — used to evaluate [schedule](/sections/documentation/ticketing/ticket-configuration/schedules) conditions (business hours vs after hours). * Optional **Status**, **Priority**, and **Type**: When set, the simulator uses those values instead of inferring them. The **Type** dropdown includes your team's change and custom ticket subtypes, including drafts. Leave status on **Default** and priority/type unset to let Serval infer what it can from the message. Category is always inferred from the ticket content. You cannot override it in the simulator. Click **Simulate**. Results include: * **Auto-set properties** — the category Serval inferred from the message. * **Rule Evaluation** — each rule in order, with which conditions matched or missed, and which rule (if any) won. * **Assignment Result** — the users or [assignment group](/sections/documentation/ticketing/ticket-configuration/assignment-groups) the matched rule would assign to, plus any workflows that rule would trigger. If nothing matched, the result shows fallthrough to your **default assignment**. Simulate after reordering rules or changing schedule conditions. Try the same message at a weekday afternoon vs a weekend evening to confirm on-hours and off-hours routing. Simulation is a dry run. It does not escalate, assign, notify, or modify tickets. *** ## Related Own tickets by org group and choose round-robin or human triage Define ticket categories used as assignment rule conditions Configure business hours schedules used in assignment rule conditions How tickets get to the right team and person # Assignment groups Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/assignment-groups Assign tickets to org groups for triage, round-robin distribution, and group-level reporting Assignment groups let a team treat an [organization group](/sections/documentation/platform/org-settings#groups) as the **owning group** on a ticket. Use them to route work to a queue (Network, HR, Desktop Support), balance load across members, and filter or report at the group level. An assignment group is separate from the individual **assignee**. A ticket can belong to a group and still have a specific person working it — or stay with the group only until someone picks it up. Assignment groups are not the same as [visibility groups](/sections/documentation/ticketing/manage-collaborate/visibility), which restrict who can see sensitive tickets. *** ## Prerequisites 1. Create or sync the org groups you need under **Org Settings → Groups** (or via [SCIM](/sections/documentation/platform/org-settings#scim)). 2. Add the right people to each group. 3. Open the team that will use those groups and go to **Team Settings → Assignment**. *** ## Set up assignment groups for a team Groups become available for a team in two ways: * **Automatically** — any group used in an [assignment rule](/sections/documentation/ticketing/ticket-configuration/assignment) or as the team's **default assignment** is included. * **Manually** — add extra groups under **Settings → Assignment groups** so agents can pick them on a ticket even when they are not used in routing. Most teams only need the automatic path: put groups in rules or default assignment and skip manual additions unless agents need more options. Go to **Team Settings → Assignment**. Create an [assignment rule](/sections/documentation/ticketing/ticket-configuration/assignment) that assigns matching tickets to a group, or set a group as the **default assignment** fallback. A single assignment rule can target **either** one assignment group **or** one or more users — not both in the same rule. Use separate rules if you need different targets. Open **Settings → Assignment groups**. Click **Add group** to include an existing org group, or **Create new group** to make one. Groups already used in rules or default assignment appear with a lock and cannot be removed from this list while they are still referenced. Under **Settings → Assignment preferences → Group member assignment**, pick how Serval chooses an individual when a ticket is routed to a group: | Option | Behavior | | - | - | | **Round-robin** (default) | Rotate evenly through the group's members and set one as the assignee. | | **Human triage** | Keep the ticket with the group only — no automatic individual assignee. Someone claims it manually. | The ticket requester is never auto-assigned from the group pool. If every member of the pool is the requester, the ticket stays without an individual assignee. To use a different option for specific groups, set **Member assignment** on the group's row under **Settings → Assignment groups**. A group left on **Team default** follows the team setting, so changing the team setting later still applies to it. For example, keep the team on **Human triage** and set only your Desktop Support group to **Round-robin**. Removing a group from **Assignment groups** clears its member assignment override. If you add the group back, it starts on **Team default** again. Turn on **Restrict assignment to team members only** if Serval should only auto-assign people who are also members of this team. The assignee picker also applies this restriction, including when the assignment group contains people outside the team. *** ## Find and manage assignment groups Under **Settings → Assignment groups**, use **Search groups or schedules** to find a group by its name or mapped work schedule. Search covers the entire list. The table displays ten groups at a time; use the previous and next controls below it to move between pages. Open the filter menu beside search and select **With schedule** or **Without schedule** to filter by work schedule mapping. Select **All groups** or **Clear filters** in the menu to reset the schedule filter. Choose a schedule in the **Work schedule** column to update it. **Add group** stays above the table, including when you filter the list. *** ## On a ticket Agents can set or clear the owning group from the ticket **Properties** panel using **Assignment group**. The menu lists groups configured for that team (from rules, default assignment, and manually added assignment groups). Changing the assignment group can also update the individual assignee according to the team's **Group member assignment** setting. You can still change the assignee separately afterward. When a ticket has an assignment group, the assignee picker offers only members of that group, plus **Unassigned**. This applies automatically, including to assigning yourself. If the group has no eligible members, the ticket can stay unassigned. Clear or change the assignment group before choosing someone outside it. Tickets without an assignment group keep their usual assignee choices, subject to the team's assignment and access settings. For bulk assignee changes, select tickets from a single assignment group. You can include tickets without a group; the picker still uses the selected group’s members. Group members can be notified when a ticket is assigned to their group. See [Notifications](/sections/documentation/ticketing/manage-collaborate/notifications). *** ## Filter and display In the ticket list: * Filter by **Assignment group**, including **My assignment groups** for groups you belong to. * Optionally show an **Assignment group** column under **Display**. Save these settings in a [saved view](/sections/documentation/ticketing/manage-collaborate/filter-sort#saved-views) if your team uses the same queue layout regularly. When you save a view, the **Save to** picker can save it to an assignment group you belong to, sharing that queue layout with every member of the group. *** ## Related Automatically route escalated tickets to users or groups Create and sync the groups used as assignment groups How tickets reach a team and then a person Filter tickets and save views by assignment group # Categories Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/categories Define and assign ticket categories to classify requests manually or with AI Categories allow you to define the different kinds of requests your team handles. You can set a ticket's category at any time from the Serval UI. If a ticket does not have a category set, Serval can also automatically classify it on escalation. *** ## How Categories Are Set There are two ways a ticket gets a category: 1. **Manually** — You can set or change a ticket's category from the ticket side panel at any time. 2. **Automatically on escalation** — When a ticket is escalated to a human agent, Serval reads the ticket content and assigns the most appropriate category from your configured list. Serval will not override a category you have already set manually. Categories are used for: * **Ticket assignment** — [Assignment rules](/sections/documentation/ticketing/ticket-configuration/assignment) use categories as one of several conditions to determine ticket assignment Go to **Team Settings** → **Categories** Click **New Category** and provide a name and description. The description helps Serval's AI accurately match tickets, so be specific about what kinds of requests belong in each category. Think about how your team naturally segments incoming requests. Common patterns include segmenting by topic. ### Example Categories | Category | Description | | - | - | | **Billing and Finance** | Questions about invoices, payments, refunds, pricing, or subscription changes | | **Design Apps Access** | Access requests for design tools like Figma, Sketch, or Adobe Creative Cloud | | **Device Issues** | Laptop problems, peripheral malfunctions, hardware troubleshooting, equipment repairs | | **Password Reset Requests** | Password resets, account lockouts, credential recovery | | **Onboarding Processes** | New hire setup, orientation questions, first-day logistics | | **Device and Computer Requests** | New laptop orders, monitor requests, equipment returns, device upgrades | *** ## Managing Categories ### Editing Categories Category names and descriptions can be created and updated on the Categories tab. ### Deleting Categories When you delete a category, any assignment rules that use it as a condition may be affected. You'll see a confirmation warning before the deletion goes through. Deleting a category may affect assignment rules that use it as a condition. *** ## Best Practices Create categories that are sufficiently different from one another to avoid confusion. Include specific keywords and examples in your category descriptions. This helps Serval accurately infer the category from ticket content. Align categories to your team's areas of expertise so they pair naturally with assignment rules. Periodically check whether tickets are landing in the right categories. Adjust descriptions or add new categories as request patterns evolve. *** ## Viewing and Changing a Ticket's Category A ticket's category is displayed in the ticket side panel under **Properties**. You can click on the category to change it or select **No category** to clear it. Ticket side panel displaying the category selector ### Ticket Activity Category changes are logged in each ticket's activity section, whether set manually or by Serval. Ticket activity feed showing a category change event *** ## Related Use categories as conditions in assignment rules for automatic ticket assignment Add flexible tags to tickets for filtering and reporting # Custom Fields Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/custom-fields Add structured data to tickets with custom fields Custom fields let you attach structured key-value data to tickets beyond the built-in properties like status, priority, and labels. Use custom fields to capture information specific to your team's processes — such as cost centers, affected systems, departments, locations. Custom fields are configured per team and apply to all tickets on that team. You can populate them manually, with AI inference, or programmatically through workflows and the public API. Custom fields live under **Settings → Ticket types** in the team sidebar. Pick a ticket type (Requests, Tasks, Incidents, etc.) to view and edit the fields it captures. *** ## Supported Field Types Each custom field has a data type that determines what values it can hold and how it appears in the UI. | Type | Name | Description | Example Value | | - | - | - | - | | **Text** | Office Location | Free-form text | `Building 3, Floor 2` | | **Number** | Cost Estimate | Numeric value | `4200` | | **Boolean** | Requires Approval | Yes or No | `Yes` | | **Date** | Target Completion | Date and time | `2026-03-15 10:30 AM` | | **Dropdown** | Request Area | Single selection from predefined options | `Hardware` | | **Multi-select** | Affected Systems | Multiple selections from predefined options | `Hardware`, `Network` | | **Item Reference** | Affected CI/Asset | Link to an item in your team's databases, optionally limited to specific item types | `LAPTOP-0042` | Dropdown and multi-select fields are useful when you want consistent, searchable values. AI inference also works with these types — the model picks from your predefined options. Each option can carry a description that tells the model when that option applies. *** ## Creating Custom Fields Team admins create custom fields in team settings. Navigate to **Settings** for your team. Select the **Ticket types** section in the team settings sidebar. Custom fields are configured per ticket type inside this page. Click **Add Field** and configure the new row: * **Field Name**: A descriptive name for the field, for example "Cost Center" or "Affected System" * **Data type**: One of the supported field types * **Item type** (Item Reference fields only): The item types the field can link to. Select one or more item types to limit the field to those tables, or leave it on **Any item type** Click the **options** button on the row to open the option editor. Each option has a **value** and a **display name**. The value is the stored identifier and is fixed once saved. The display name is the label people see, and you can rename it any time. Click the description icon on an option to add an optional **description** that says when that option applies. On a **Request Area** field, for example, "Hardware" might carry "Laptops, monitors, docking stations, and other physical equipment, including replacements and repairs." AI inference reads these descriptions to choose between options, so write them the way you would brief a new agent. Click **Done** to keep your edits. Click **Save changes** to make the field available on tickets. You can give a field its own description only when you create it from a ticket's expanded field section. **Settings → Ticket types** has no field description input, and you can't edit one after creation. Put guidance for AI inference on the options instead. Custom fields apply to all tickets on the team. There is no way to limit a field to a subset of tickets. *** ## Setting Values on Tickets ### From the Ticket Detail On change tickets, select the **Fields** tab next to **Activity**. Other ticket types keep custom fields in the properties side panel, with populated values also available in the properties bar. Fields appear in their configured sections, including empty fields marked **Not set**: 1. Hover over or focus a field value, then click it to edit. For an empty field, click **Not set**. 2. Enter or select a value 3. Click **Save** to confirm. On change tickets, long text values show a three-line preview. Click the value to open the full text in the editor. On read-only change tickets, click **show more** to read the full value and **show less** to collapse it. To clear a field value, hover over or focus the field, then click its clear icon. Read-only tickets display field values without editing controls. The change ticket **Fields** tab displays groups in one column, with wide text previews capped at three lines. Expand an individual group to focus on its fields. Team admins can expand a section, then click **Add field** in the expanded editor to create a field. ### With AI Inference Serval can automatically populate custom fields using AI, similar to how AI infers labels. When enabled, the model reads the ticket's name, description, and conversation history to determine appropriate values. AI inference supports **Text**, **Number**, **Boolean**, **Dropdown**, and **Multi-select** field types. For dropdown and multi-select fields, the model picks from your predefined options. It sees each option's display name and description, so it judges an option with no description by its name alone. When the model sets a value, the ticket activity records the reason it chose that option. Navigate to **Settings** for your team. Select the **Ticket types** section in the team settings sidebar. Open a ticket type and turn on **Set fields with AI** in the **Custom fields** card. The setting applies to every ticket type on the team. If inference keeps leaving a dropdown empty or picking the wrong option, add or sharpen the option descriptions. The model only sets a field when the ticket clearly indicates a value, and a bare option name like "Confidential" seldom gives it enough to go on. When enabled, inference runs automatically each time a ticket is created or updated. It only populates fields that do not already have a value — it will not overwrite values set by an agent, workflow, or previous inference run. AI inference does not support **Date** fields. If you need dates populated automatically, use a workflow. ### With Catalyst Workflows have built-in actions for reading and writing custom fields. Use [Catalyst](/sections/documentation/catalyst/overview) to describe what you want in natural language, or call the helpers directly in code. **Discover available fields** — list all custom field definitions for the team: ```typescript theme={null} const options = await serval.common.listCustomFieldOptions({ teamId: ctx.currentTeam.id, }); ``` **Read current values** on a ticket: ```typescript theme={null} const values = await serval.common.getTicketCustomFieldValues({ ticketId }); ``` **Set values** on a ticket: ```typescript theme={null} await serval.common.setTicketCustomFieldValues({ ticketId, fieldValueInputs: [ { fieldKey: "cost-center", value: "ENG-042" }, { fieldKey: "affected-system", value: "Billing" }, ], }); ``` ### With the Public API You can also set and read custom field values directly via the REST API. **Set custom field values:** ```bash cURL theme={null} curl -X PUT 'https://api.serval.com/v2/tickets/{ticket_id}/custom-field-values' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -d '{ "field_values": [ { "field_key": "cost-center", "value": "ENG-042" } ] }' ``` **Read custom field values:** ```bash cURL theme={null} curl -X GET 'https://api.serval.com/v2/tickets/{ticket_id}/custom-field-values' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' ``` **List available custom field definitions:** ```bash cURL theme={null} curl -X GET 'https://api.serval.com/v2/teams/{team_id}/custom-field-options' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' ``` **Create a custom field definition:** ```bash cURL theme={null} curl -X POST 'https://api.serval.com/v2/teams/{team_id}/custom-field-options' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -d '{ "ticket_type": "TICKET_TYPE_REQUEST", "field_name": "Affected system", "data_type": "ENUM", "enum_options": [ { "value": "Billing", "display_name": "Billing", "display_order": 0, "description": "Invoices, refunds, or the billing portal" }, { "value": "Okta", "display_name": "Okta", "display_order": 1 } ] }' ``` Each ticket type has its own field schema, so a field created on `TICKET_TYPE_REQUEST` does not exist on `TICKET_TYPE_JOURNEY`. `ENUM` and `MULTI_SELECT` require `enum_options`; every other data type rejects them. Each option's `description` is optional and is what AI inference reads to choose between options. For change tickets, also pass the `ticket_subtype` whose schema you're editing. Creating fields requires the `create_custom_field_settings` permission. On a scoped API key, grant the `ticket-fields:write` scope. Fields are identified by their `field_key` in the public API. *** ## Filtering by Custom Fields Custom fields are available as filters in the ticket list: 1. Click the **Filter** button 2. Select a custom field from the filter menu 3. Choose an operator and value Filter by ticket type to select only fields that apply to those types. This also distinguishes custom ticket types: a Security Incident field doesn't apply to another custom type. An **is empty** filter matches only tickets of a type that uses that field. For dropdown and multi-select fields, you select from the predefined options. For text fields, you enter a search term. For number and date fields, you can use comparison operators (greater than, less than, etc.). *** ## Removing Dropdown Options You can remove individual options from a **Dropdown** or **Multi-select** field. In **Settings → Ticket types**, expand the ticket type, open the field's option editor, delete the options you no longer need, and save. Serval asks you to confirm before saving, because removing an option can't be undone from the UI. Re-adding the same value later creates a new option rather than restoring the old one. Tickets that already use a removed option keep their current value. The option simply can't be selected again. A field must always keep at least one option, so you can't remove them all. *** ## Hiding fields You can hide a custom field from views without deprecating it. A hidden field stays fully readable and writable (workflows, AI, and the public API still use it), but is hidden from list columns, filters, sorting, grouping, and journey and queue views. On tickets, find it in the expandable hidden-fields disclosure. From **Settings → Ticket types**, open the field's overflow menu and choose **Hide from views** (it gets a **Hidden** badge); choose **Show in views** to bring it back. Saved views that referenced the field keep working, and deprecation takes precedence: a field that's both deprecated and hidden shows only in the deprecated section. *** ## Deprecating and Restoring Fields If a custom field is no longer needed, you can deprecate. Deprecating a field: * Hides it from new edits on tickets — agents can no longer set or change its value * Preserves all existing data — tickets that already have a value for the field retain it To deprecate a field, go to **Settings → Ticket types**, expand the ticket type the field belongs to, and click the remove option on the field. To restore a deprecated field and make it editable again, find it in the deprecated section and click **Restore**. Deprecation is reversible. If you change your mind or need the field again later, restoring it brings back full editing capability with all historical data intact. You can't restore a deprecated field while an active field on the same ticket type has its name. Rename or deprecate the active field first. *** ## Changing a Field's Data Type A field's data type can't be changed once it's saved. Workflows, views, and dashboards that use the field rely on its type, and existing ticket values can't always be converted. To use a different type, deprecate the field and create a new one with the same name and the new type. Tickets that already have a value keep it on the deprecated field, and new values go to the new field. Update any workflows, views, or dashboards that used the old field to use the new one. # Custom Ticket Types Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/custom-ticket-types Define your own team-specific ticket types with their own lifecycle, transitions, workflows, and fields Beyond the built-in ticket types — Request, Incident, Major Incident, Change, and Problem — Serval lets each team define its own **custom ticket types**. A custom type bundles its own lifecycle, status transitions, entry workflows, and custom fields, so you can model a process that doesn't fit the standard types. *** ## What Is a Custom Ticket Type? A **custom ticket type** is a ticket type you author for your team's specific needs — for example, Legal Intake, Onboarding, Access Review, or Facilities Request. Each custom type is fully self-contained: * Its own **lifecycle** — the statuses a ticket moves through from creation to closure * Its own **transition rules** — which status can move to which, with optional conditions * Its own **entry workflows** — automations that run when a ticket enters a status * Its own **custom fields** — the information captured on tickets of that type Custom types use the same underlying model as [change models](/sections/documentation/ticketing/change-management), so everything you can configure on a change model — lifecycle, transitions, automations, and fields — is available on a custom type. Reach for a custom type when a process needs its own distinct lifecycle and fields. If you only need different statuses or SLAs on an existing type, configure those directly instead — see [Statuses](/sections/documentation/ticketing/ticket-configuration/statuses) and [SLAs](/sections/documentation/ticketing/ticket-configuration/slas). *** ## Creating a Custom Type Custom types are configured in **Team Settings → Ticket Types**, in the **Custom Types** group of the left sidebar. Go to **Team Settings → Ticket Types**. In the sidebar, find the **Custom Types** group. Click **Create custom type**. Give it a name (for example, "Legal Intake") and an identifier. The identifier is derived from the name and used to reference the type. In the editor, define the statuses the type moves through, which status is the starting point, and the order they appear in. Set which statuses can transition to which, add any conditions that must be met to advance, and attach entry workflows that run when a ticket enters a status. Configure the custom fields captured on tickets of this type. A new custom type starts as a **draft**. When it is ready, publish it to make it available for creating tickets. Creating and editing custom types requires the permission to manage ticket models, so this is typically limited to team managers and administrators. *** ## Draft, Published, and Deprecated Custom types move through a lifecycle of their own, so you can build and retire them without disrupting existing tickets. | State | What it means | | :- | :- | | **Draft** | The type is being configured. It isn't offered when creating tickets yet. | | **Published** | The type is live and available in the Create Ticket dialog. | | **Deprecated** | No new tickets can be created with the type, but existing tickets keep it and remain visible and filterable. | Publish a type when it's ready, and deprecate it when you no longer want new tickets created with it. Deprecating is the safe way to retire a type that already has tickets — nothing is lost. *** ## Configuring a Custom Type Everything about a custom type is configured in its editor under **Team Settings → Ticket Types**. ### Lifecycle and Statuses Each custom type has its own set of statuses and a designated starting status. When a ticket of that type is created, it begins at the starting status. You can manage the pool of statuses available to custom types from **Team Settings → Statuses**, under the **Custom** tab. ### Transition Rules Transitions control how a ticket moves between statuses. Each transition can carry a condition that must be satisfied before the ticket can advance — for example, requiring certain fields to be filled. See [Statuses](/sections/documentation/ticketing/ticket-configuration/statuses) for more on building status flows. ### Entry Workflows Attach a [workflow](/sections/documentation/workflows/overview) to a status so it runs automatically when a ticket enters that status — for example, to request an approval, send a notification, or run a validation check. ### Custom Fields Each custom type has its own custom fields, tailored to the information that type of ticket needs to capture. See [Custom Fields](/sections/documentation/ticketing/ticket-configuration/custom-fields). *** ## Working with Custom-Typed Tickets **Creating a ticket** — Published custom types appear directly in the ticket type selector of the Create Ticket dialog. Selecting one starts the ticket at that type's initial status and shows its custom fields. **Creating from Slack** — Published custom types also appear in the **Type** dropdown of Slack's **Create a ticket** form once you pick a team. Choosing one asks for a title and description instead of an initial message, and Serval doesn't reply in the ticket thread. Custom types can't be filed with the team set to auto-detect. **Filtering** — Custom types appear in the ticket filters so you can slice ticket lists and views by type. Deprecated types stay filterable so their existing tickets remain reachable. **On the ticket** — A custom-typed ticket displays its type name wherever tickets are listed or opened, so it's always clear which type a ticket belongs to. *** ## Deleting vs. Deprecating * **Delete** a custom type only when no tickets use it. Deleting removes the type along with its lifecycle, transitions, and entry workflows. A draft that was never used can be safely deleted. * **Deprecate** a type that already has tickets. Deprecating stops new tickets while keeping existing ones intact and filterable. If you try to delete a type that still has tickets, Serval blocks the deletion and points you to deprecate it instead. *** ## Related Pages * [Ticket Types](/sections/documentation/ticketing/ticket-configuration/ticket-types) * [Change Management](/sections/documentation/ticketing/change-management) * [Statuses](/sections/documentation/ticketing/ticket-configuration/statuses) * [Custom Fields](/sections/documentation/ticketing/ticket-configuration/custom-fields) * [Workflows](/sections/documentation/workflows/overview) # Labels Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/labels Mark and organize tickets with custom labels Labels provide a flexible way to organize tickets beyond the standard attributes. Use labels to tag tickets by request area, department, location, or any custom grouping your team needs. *** ## How Labels Work Labels are colored tags that you can apply to tickets for: * **Grouping** - Group related tickets (e.g., "Billing", "Feature Request", "Bug") * **Filtering** - Quickly find tickets with specific labels * **Reporting** - Analyze ticket volume by label * **Visual identification** - Spot ticket types at a glance in list view *** ## Applying Labels ### From the Ticket List Click the labels column on any ticket to add or remove labels: 1. Click the **Labels** area on the ticket row 2. Select labels from the dropdown 3. Click away to save You can apply multiple labels to a single ticket. ### From the Ticket Detail Open a ticket and use the labels field in the right panel: *** ## Creating Labels Admins can create new labels in team settings: Navigate to **Settings** for your team. Go to the **Labels** section. Click **Add Label** and configure: * **Name** - Short, descriptive name * **Color** - Choose a color for visual identification * **Description** - Explain when to use this label Click **Create** to make the label available. *** ## Label Best Practices Start with a small set of labels. You can always add more as needs emerge. Establish naming conventions (e.g., lowercase, no spaces) for easy searching. Use similar colors for related labels (e.g., all product areas in blue shades). Add clear descriptions so team members know when to apply each label. ### Common Label Values * Access * Hardware * Software * Networking * Onboarding * IT * HR * Facilities * Finance * Security * HQ * Remote * NYC Office * SF Office * New Hire * VIP * Executive * Audit-Related *** ## Filtering by Labels Use labels to filter your ticket list: 1. Click the **Filter** button 2. Select **Labels** 3. Choose one or more labels to filter by When filtering by multiple labels, tickets matching **any** of the selected labels are shown. # Priorities Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/priorities Configure priority levels to triage and handle tickets appropriately Priorities help your team understand which tickets need attention first. Configure priority levels that match your organization's urgency definitions and SLA requirements. *** ## Understanding Priorities Priorities indicate how urgently a ticket needs attention. Higher priority tickets: * Appear at the top of sorted lists * Can trigger shorter SLA targets when priority-based SLA policies are configured *** ## Default Priority Levels Serval includes common priority levels out of the box: | Priority | Typical Use | | :- | :- | | **Critical** | Complete outage, security incident, or blocker affecting many users | | **High** | Significant impact, workaround not available, time-sensitive | | **Medium** | Moderate impact, workaround available, standard timeline | | **Low** | Minimal impact, convenience request, no deadline | You can customize these names and add additional levels to match your organization's terminology. *** ## Configuring Priorities ### Add a Priority Go to **Team Settings** → **Priorities**. Click **Add Priority**. | Field | Description | | :- | :- | | **Name** | Priority level name (e.g., "Urgent") | | **Description** | Criteria for when to use this priority | | **Examples** | Real-world scenarios that warrant this priority | Drag priorities to set their relative urgency order. ### Writing Good Descriptions Include specific criteria in your priority descriptions: **Good description:** > Use for issues affecting more than 10 users, causing revenue loss, or blocking critical business processes. Examples: Payment processing down, login system unavailable, data breach. **Poor description:** > Very urgent issues. Detailed descriptions help both team members and Serval's AI assign priorities consistently. *** ## AI Priority Assignment Serval automatically assigns priorities to incoming tickets based on: * Message content and urgency signals * Number of affected users mentioned * Keywords like "urgent", "ASAP", "critical" * Your priority descriptions and examples ### Improving AI Accuracy Include 3-5 real examples in each priority description Define measurable thresholds (e.g., "affects >10 users") Regularly review AI assignments and correct mistakes Refine descriptions based on patterns you observe *** ## Priority and SLAs You can create separate SLA policies for different priority levels so that higher priority tickets have shorter resolution targets. For example, you might configure a 4-hour SLA for critical tickets and a 72-hour SLA for low priority requests. Configure SLA policies and their auto-attach criteria (including priority) in **Team Settings** → **SLAs**. See the [SLAs guide](/sections/documentation/ticketing/ticket-configuration/slas) for details. *** ## Changing Ticket Priority Change priority from list view, detail view, or chat. See [Updating Ticket Properties](/sections/documentation/ticketing/manage-collaborate/update-ticket-properties) for detailed instructions. *** *** ## Related Learn how to change ticket priority from list view, detail view, or chat Configure SLA timelines based on priority ## Setting priorities from workflows or the API Priority IDs belong to a specific team. When you copy a workflow between teams, look up the destination team's priorities with `GET /v2/priorities?teamId=` before setting `priorityId` on a ticket. Match the priority level from that response instead of reusing a priority ID from another team. Updating a ticket with a nonexistent priority ID or a priority from another team returns HTTP 400 (`INVALID_ARGUMENT`). Choose a priority belonging to the ticket's team before retrying. # Schedules Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/schedules Define business hours schedules for SLA tracking and assignment rules Schedules define your team's working hours. They are used by [SLA policies](/sections/documentation/ticketing/ticket-configuration/slas) to track resolution time only during business hours, and by [assignment rules](/sections/documentation/ticketing/ticket-configuration/assignment) to route tickets differently based on the time of day. *** ## How Schedules Work A schedule specifies which hours of each day of the week your team is available, along with a timezone. For example, a typical schedule might define Monday through Friday, 9:00 AM to 5:00 PM in US Eastern time. Schedules are reusable across your team — once created, the same schedule can be referenced by multiple SLA policies and assignment rules. *** ## Creating a Schedule Go to **Team Settings** → **Schedules**. Click **New Schedule**. A new schedule is created with default hours (Monday–Friday, 9 AM – 5 PM in your local timezone). | Field | Description | | :- | :- | | **Name** | A descriptive name for the schedule (e.g., "US Business Hours", "EMEA Support Hours") | | **Timezone** | The time zone used to evaluate the schedule (e.g., America/New\_York, Europe/London). Set a fixed zone, or choose **Requester's time zone** to read the schedule's hours in each ticket requester's own profile time zone, with a **Fallback time zone** for requesters who don't have one | | **Weekly hours** | For each day of the week, toggle whether the day is active and set the start and end times. Use the **+** button on a day to add more time ranges to it (e.g., 9:00–12:00 and 13:00–17:00 to exclude a lunch hour) | A schedule set to **Requester's time zone** can only be used by requester follow-ups, so a follow-up reminder lands during the requester's own working hours. SLA policies and assignment rules require a schedule with a fixed time zone. **Overnight coverage** — a shift that crosses midnight (for example, off-hours support from 11:00 PM to 6:00 AM) is defined as two ranges: end the first day at midnight by setting its end time to 12:00 AM, and add an early-morning range on the following day. For nightly 11 PM–6 AM coverage, give each day the ranges 12:00 AM–6:00 AM and 11:00 PM–12:00 AM. *** ## Where Schedules Are Used ### Assignment Rules [Assignment rules](/sections/documentation/ticketing/ticket-configuration/assignment) can include a **schedule condition** that matches when the ticket escalation time falls within a schedule's hours. This lets you route tickets differently during and outside of business hours. For example, you might create two assignment rules for urgent tickets: * During "US Business Hours" → assign to the primary support group * During "After Hours On-Call" → assign to the on-call rotation group ### SLA Policies [SLA policies](/sections/documentation/ticketing/ticket-configuration/slas) can use a schedule to count time only during business hours. When an SLA uses business hours, the resolution timer pauses outside of the schedule's defined hours and resumes when working hours begin again. *** ## Managing Schedules ### Editing a Schedule Click on any schedule card to expand it and edit the name, timezone, or weekly hours. Changes are saved automatically. ### Deleting a Schedule Click the delete button on a schedule card. You'll see a confirmation prompt before the schedule is removed. Deleting a schedule affects any SLA policies that reference it. Review your SLA configurations after removing a schedule. *** ## Related Use schedules as conditions in assignment rules Track resolution times using business hours schedules # The Serval Ticket Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/serval-ticket Understand ticket anatomy, properties, and configuration options Every request in Serval becomes a ticket. This guide covers the components of a ticket and how to configure them. ## Accessing team settings To configure ticket attributes for your team, navigate to **Settings** for your team. *** ## Ticket properties Each ticket contains configurable properties that control how it's categorized, prioritized, and routed: Current workflow stage: To Do, In Progress, Done, or Canceled Urgency level that determines handling order and SLA timelines AI-inferred property used for classification and routing Team member or Serval responsible for resolving the ticket Time remaining to meet response and resolution commitments Custom tags for grouping and filtering Classification as Request, Incident, or Change Target date for ticket resolution, with overdue indicators Sub-items for breaking down complex tickets Connections to synced external ticketing systems By default, tickets are assigned to Serval. The AI will continue working on the ticket until it either resolves the issue or escalates to a human agent. ### Built-in fields Each ticket also has these built-in fields: | Field | Description | | :- | :- | | **Title** | Brief summary of the request, auto-generated from the message | | **Description** | Full details of the request | | **Requester** | The person who submitted the request | | **Team** | Which team is responsible for handling | | **Due Date** | Target resolution date, with overdue indicators when past due | | **Created** | When the ticket was submitted | | **Updated** | When the ticket was last modified | *** ## Built-in fields vs custom fields Serval gives you three ways to describe what a ticket is about. They look similar on the surface but serve different purposes. Choosing the right one keeps your routing clean and your data useful. | | Built-in | Labels | Custom Fields | | :- | :- | :- | :- | | **Multiplicity** | Exactly one per ticket | Any number (including none) | Any number, each with its own type | | **Required** | Yes | No | Configurable per field | | **Primary use** | Routing, SLAs, filtering | Grouping, search, trends | Forms, automation, integrations | ### Built-in fields Category, Status, and Priority are built-in fields used to configure **routing** and **SLA, approval, and other policies**. These fields exist on every ticket. ### When to use labels vs custom fields * **Labels** - lightweight, cross-cutting tags that don't affect routing. Use them to flag themes like a specific project, initiative, or known issue. * **Custom fields** - structured data entry (dates, numbers, dropdowns, text) for process-specific information that powers forms, approvals, and integrations. *** ## Ticket detail view Click any ticket to open the detail view with two main areas: * **Activity** - The conversation between requester, Serval, and team members. Messages, workflow runs, and property changes share one timeline. Use **Filter** to show all activity or narrow to messages, internal notes, and other event types. See [Resolving Tickets](/sections/documentation/ticketing/resolving-tickets) for how to respond and use Copilot. * **Properties** - The **Properties** panel on the right lists ticket fields for quick editing. When the panel is closed, edit from the property pills in the page header. On smaller screens, use **Open properties** for the full panel. See [Updating Ticket Properties](/sections/documentation/ticketing/manage-collaborate/update-ticket-properties) for details. *** ## Configuration guides *** ## Related Guide to working through tickets Automate ticket handling Knowledge base for AI responses Track ticket metrics # SLAs Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/slas Configure Service Level Agreements to track resolution time and time-to-first-response commitments Service Level Agreements (SLAs) define your team's commitments — how quickly tickets should be resolved, how quickly a human agent should respond, and so on. Configure SLA policies to track performance and surface tickets that are at risk of breaching. *** Label conditions reference the selected label's ID. Renaming that label preserves the condition; deleting it and creating another label with the same name does not reconnect the condition. ## Understanding SLAs An SLA policy measures one specific commitment against a target duration. A policy has three pieces: * **What to measure** — the *metric* (e.g. time to resolution, time to first response). * **When the clock starts** — the *starting point* (when the SLA is attached, or backdated to when the ticket was created). * **What stops the clock** — implied by the metric. Resolution stops on ticket closure; first response stops on the first reply from a member of the ticket's team. Tickets that match the policy's criteria are tracked automatically. A single ticket can have several SLAs running at once, one per *policy group*: policies in different groups run concurrently, while policies in the same group share a single slot (the first matching policy attaches). A policy without a group uses its metric as the group, so by default a ticket carries at most one resolution SLA and one first-response SLA. Named groups unlock several same-metric SLAs on one ticket — for example a "Resolution — full time" SLA alongside a "Resolution — excluding vendor time" variant that pauses while you wait on a third party. *** ## Creating an SLA Policy Go to **Team Settings** → **SLAs**. Click **Add SLA**. | Field | Description | | :- | :- | | **Name** | Descriptive name (e.g., "Critical Priority Resolution") | | **Target duration** | Time limit for the metric — choose from presets or set a custom duration in days, hours, and minutes | | **Calendar type** | Whether to track against calendar time (24/7) or business hours | | **What to measure** | The metric the SLA tracks. See [Metrics](#metrics) below | | **Start the clock** | When the clock begins counting. See [Starting Points](#starting-points) below | | **Auto-attach criteria** | Conditions that determine which tickets this SLA applies to (e.g., priority, status, labels, groups) | Click **Create** to activate the SLA policy. Matching tickets will begin tracking automatically. *** ## Metrics The metric determines what the SLA is measuring — and therefore what stops the clock. | Metric | What it tracks | Clock stops when | | :- | :- | :- | | **Time to resolution** | The total time a ticket is open | Ticket status reaches Done or Canceled | | **Time to first human response** | The time until the first member of the ticket's team replies | A member of the ticket's team (not the requester, not AI, not an internal note) posts a public message on the ticket after the clock started, **or** the ticket is resolved without one | First-human-response SLAs only count *human* messages from your team. AI assistant messages, internal notes, system-generated messages, and messages from the ticket's requester do not stop the clock — first response is specifically about a person on the team picking up the conversation. Public replies received through connected channels, including inbound email, count toward first-human-response SLAs. The clock stops at the reply's timestamp, even if Serval receives the reply later. Team membership is what makes a reply count. If the help desk runs in a shared chat channel, a colleague of the requester can answer before your team does; that reply doesn't stop the clock, because it isn't your team responding. Anyone with a seat on the ticket's team counts, whether they hold it directly or through a group mapped to the team. If a ticket is resolved before a human ever responds (for example, fully handled by AI), the SLA closes out at resolution time. It records as **Met** if resolution happened within the SLA's target duration, or **Breached** if it took longer — same met/breached logic as a normal completion. *** ## Starting Points The starting point controls *when* the clock begins. | Starting point | When it starts | | :- | :- | | **When the SLA is attached** | The moment the SLA attaches to the ticket (default) | | **When the ticket was created** | Backdated to the ticket's creation time. Useful when tickets sit in a queue before being routed | To measure time-to-first-human-response *after* a specific event (e.g. after escalation to a human), express the event with auto-attach criteria rather than the starting point. For example, combine the *Time to first human response* metric with `When the SLA is attached` and add `ticket.escalation_level = human` to the auto-attach criteria — the SLA will only attach (and start counting) once the ticket has been escalated. *** ## Calendar Time vs. Business Hours When creating an SLA, you choose how time is counted: * **Calendar time (24/7)** — The clock runs continuously, including nights and weekends. Use this for critical issues that require around-the-clock attention. * **Business hours** — The clock only runs during your configured working schedule. Use this for standard requests where resolution outside business hours isn't expected. ### Configuring a Business Hours Schedule If you select business hours, you'll choose a [schedule](/sections/documentation/ticketing/ticket-configuration/schedules) that defines your team's working days and hours. Schedules include a timezone and per-day time windows (e.g., Monday–Friday, 9 AM – 5 PM). Schedules are reusable — the same schedule can be shared across SLA policies and [assignment rules](/sections/documentation/ticketing/ticket-configuration/assignment). *** ## Auto-Attach Criteria SLA policies can automatically apply to tickets based on conditions like: * **Priority:** Apply to tickets of a specific priority level * **Labels:** Apply to tickets with specific labels * **Assignment group:** Apply to tickets assigned to one of the [assignment groups](/sections/documentation/ticketing/ticket-configuration/assignment-groups) you select. Available once your team has assignment groups configured. * **Requester's field:** Apply based on an attribute of the ticket requester, such as their department, job title, email, timezone, or locale, or a user custom field where enabled. Type a value for text fields, including department. For custom fields with predefined options, select the values to match from a menu. Each criterion can match on **is** or **is not**. For example, attach an SLA to every ticket whose *Priority is not Low*. The same **is** / **is not** option applies to [pause conditions](#sla-pausing). Select multiple priorities, labels, ticket types, categories, assignees, assignment groups, or requester groups within one condition. Positive conditions match **any** selected value. Negative conditions match **none** of the selected values. For requester fields that hold multiple values, **is not** excludes a requester when any selected value is present. For priority, assignment group, category, ticket type, and label menus, multiple selections show the first two values and a count of any additional values. Hover over or focus the menu to see full names, even for a single selection. For example, to cover Medium, Low, and No priority tickets while excluding tickets labeled Serval Ticket or Spam, use: * **Priority**: Select Medium, Low, and No priority. * **AND Labels**: Choose **is not** and select Serval Ticket and Spam. A ticket with either excluded label doesn't match, even if its priority matches. **Has no labels** instead matches tickets with no labels at all; switch it to **is not** to match tickets with at least one label. This lets you create different SLA targets for different types of tickets. For example, you might have a 4-hour SLA for critical priority tickets and a 72-hour SLA for low priority requests. *** ## Attach and remove SLAs from workflows To start an SLA at a particular workflow step, create a policy with no **Auto-attach criteria** and set **Start the clock** to **When the SLA is attached**. A policy without criteria attaches only when explicitly requested. Use the Serval SDK from your workflow: ```ts theme={null} const { ticketSlaId } = await serval.common.attachSlaToTicket({ ticketId, slaDefinitionId, }); await serval.common.detachSlaFromTicket({ ticketId, ticketSlaId }); ``` The policy must belong to the ticket's team. Keep the returned `ticketSlaId` to remove that specific attachment later. Attaching the same policy while its instance is active returns that instance without resetting its clock. Attaching a different policy in the same policy group replaces the current instance; other groups remain unchanged. After completion or removal, another attach can create a new instance. The policy's starting point, business calendar, and pause rules still apply, and an instance can complete immediately if its completion event has already occurred. Removing an already completed or cancelled instance leaves it unchanged. Removal does not prevent automatic matching from attaching an SLA on a later ticket update. Use a policy without attachment criteria when the workflow should control attachment exclusively. *** ## SLA Pausing You can configure pause conditions so the SLA timer stops when the ticket is in certain states. This prevents your team from being penalized for time spent waiting on external parties. Common pause scenarios: * **Waiting on requester** — Pause while waiting for the requester to provide more information * **Waiting on vendor** — Pause while waiting for a third-party response * **On hold** — Pause for tickets that are intentionally paused You can select multiple statuses or labels in one pause condition. For example, select both Waiting on requester and Waiting on vendor to pause during either status. Label exclusions use the same any/none behavior as attachment criteria. Pause conditions are configured per SLA policy. The timer resumes automatically when the pause condition is no longer met. *** ## SLA Tracking ### SLA Status Tickets tracked by an SLA policy show their SLA status: * **On track** — The ticket is within its SLA target * **At risk** — The ticket is approaching its SLA deadline * **Breached** — The ticket has exceeded its SLA deadline ### SLA column in ticket lists Add the **SLA** column to any ticket list to see how much time each ticket has before its SLA breaches. The column is hidden by default—turn it on from the ticket list's column picker. Each cell shows the ticket's most urgent active SLA: * **Time remaining**: a live countdown to the breach deadline. It turns red in the final hour. * **Overdue**: how long the SLA has been past its deadline. * **Paused**: the SLA timer is currently paused. * **Met** or **Failed**: the SLA finished within, or past, its target. Sort by the column to bring the tickets closest to breaching to the top. ### When SLA Tracking Ends SLA tracking stops when the metric's completion event fires: * **Resolution SLAs** stop when the ticket reaches a "Done" or "Canceled" status. * **First-human-response SLAs** stop when a human agent posts the first qualifying reply on the ticket after the clock started, or when the ticket is resolved without one. You can also **manually detach** an SLA from a ticket by opening the SLA row in the ticket sidepanel, expanding the picker, and clicking **Remove SLA**. The detached SLA is recorded in the ticket activity timeline; other SLAs on the ticket are unaffected. *** ## SLA Reporting Track SLA performance in analytics: The analytics dashboard includes an SLA performance chart that shows the percentage of tickets meeting SLA targets vs. breaching. You can filter the chart by priority, assignee, or other attributes to drill into specific areas. Use the SLA filter in the ticket list to quickly find tickets that are at risk or breached and need immediate attention. *** ## Common Questions Yes. You can create different policies for different ticket types using auto-attach criteria. For example, one policy for critical tickets with a 4-hour target and another for low priority with a 72-hour target. A ticket can have one active SLA *per policy group*. Policies without a group use their metric as the group, so by default one resolution SLA and one first-response SLA can coexist. If two policies in the same group both match a ticket, the first matching policy (by name order) attaches and the rest are skipped — use this to build priority ladders, where each rung's auto-attach criteria target a different priority. Policies in different groups all attach and track independently. The ticket's headline SLA status reflects the most urgent of the active SLAs (a breached SLA outranks an in-progress one; in-progress outranks paused; if two are tied, the one breaching soonest wins). Yes — that's the point of separating *what to measure* from *when the clock starts*. Configure two policies (e.g. "Resolve within 4h from creation" and "First response within 15m from attachment"), and both will track independently. The ticket sidepanel shows one row per SLA slot. Yes — give each variant its own *policy group*. For example, create groups "Resolution — full time" (no pause conditions), "Resolution — excluding requester time" (pauses on a *Waiting on requester* status), and "Resolution — excluding vendor time" (pauses on *Waiting on vendor*). One SLA from each group attaches, and each clock pauses by its own rules, so you can report total time, time excluding the requester, and time excluding the vendor side by side. Within each group you can still build a priority ladder with several target durations. All policies in one group must measure the same metric, and the ticket sidepanel labels each row with its group name. Yes. Updating an SLA policy affects how future tickets are tracked. Existing tickets that already have the SLA attached continue with their original target. Filter your ticket list by SLA status to find at-risk or breached tickets. You can also use the SLA performance chart in analytics to see compliance trends. Open the ticket, expand the SLA row in the sidepanel, and select **Remove SLA**. The SLA moves to a "cancelled" state — it stays in the ticket's activity history but no longer counts toward breach scanning. Other SLAs on the ticket are untouched. # Statuses Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/statuses Configure ticket workflow stages with custom statuses Statuses track where tickets are in your workflow. Create custom statuses that match how your team works. *** ## Understanding Statuses Every ticket has a status that indicates its current state. Statuses are organized into four categories, and can be completely customized to fit your company's needs. Tickets waiting to be started Tickets actively being worked on Completed tickets Tickets closed without resolution You can create multiple custom statuses within each category. For example, "In Progress" might include: * Investigating * Waiting on Customer * Waiting on Vendor * In Review *** ## Creating Statuses Navigate to **Team Settings** → **Statuses**. Click **Add Status**. Fill in the status details: | Field | Description | | :- | :- | | **Name** | Short, action-oriented name (e.g., "Awaiting Approval") | | **Category** | Which category this status belongs to | | **Description** | When to use this status (helps AI assignment) | Click **Create** to add the status. Write detailed descriptions with examples. Serval's AI uses these descriptions to automatically assign statuses to incoming tickets. *** ## Default Status Every team must have a default status in the "To Do" category. New tickets are automatically assigned this status. To change the default: 1. Go to **Team Settings** → **Statuses** 2. Find the status you want as default 3. Click the **...** menu and select **Set as Default** *** ## AI Status Assignment Serval's AI can automatically assign statuses based on ticket content and conversation: * **New tickets** - AI assigns initial status based on the request * **Updates** - AI may suggest status changes based on conversation (e.g., moving to "Waiting on Customer" after asking a question) ### Enabling AI Assignment Toggle AI status assignment in team settings: 1. Go to **Team Settings** → **Statuses** 2. Enable **AI status assignment** 3. Provide detailed status descriptions for best results AI suggestions appear as recommendations. Team members can always override with manual selection. *** ## Status Transitions Change ticket status from list view, detail view, or chat. See [Updating Ticket Properties](/sections/documentation/ticketing/manage-collaborate/update-ticket-properties) for detailed instructions. ### Automatic Transitions Configure automatic status changes: New tickets automatically get the default "To Do" status. When a ticket is resolved (via AI or manually), it moves to a "Done" status. Workflows can automatically update ticket status as part of their execution. ### Transition rules By default, a ticket can move from any status to any other. To constrain the allowed moves for a ticket type (Request, Incident, or Problem), open it under **Team Settings → Ticket types** and click **Enable transitions**. Serval seeds a starter state machine so no ticket is ever stranded; edit it to set which statuses can move to which, optionally gating a transition on built-in or custom fields. Once on, transitions are enforced everywhere a status changes for people, AI, and workflows alike: Serval's AI proposes only valid next statuses, pickers gray out disallowed moves, and rule-breaking manual updates are blocked (Serval won't let you remove a transition that would strand live tickets). Click **Turn off transitions** to lift the constraints. Change models keep their built-in ITIL lifecycle regardless. Tasks use a fixed, system-managed status set and don't support custom transitions. *** ## Locking statuses Mark a **Done** or **Canceled** status as **locked** to stop a ticket accepting new requester replies once it reaches that status. Open **Team Settings** → **Statuses**, find a status in the Done or Canceled category, and turn on **Locked**. Only those two categories can be locked. While a ticket sits in a locked status: * Requesters can't reply. The web reply composer becomes a closed-ticket notice, and replies sent from Slack or Microsoft Teams are dropped with a notice that the ticket is no longer accepting replies. * Team members can still add internal notes, and Serval's AI stops suggesting status changes and won't move the ticket out of a locked status on its own. * Moving the ticket to an unlocked status (manually) reopens it to replies. *** ## Status Best Practices "Awaiting Customer Response" is clearer than "Pending" 5-8 statuses per category is usually sufficient. Too many creates confusion. Statuses should reflect actual stages in how you handle tickets Detailed descriptions improve AI accuracy and help team members choose correctly ### Example Status Configurations **To Do:** New, Triaged **In Progress:** Investigating, Waiting on User, Waiting on Vendor, Implementing Fix **Done:** Resolved, Resolved - Known Issue **Canceled:** Duplicate, Cannot Reproduce, Won't Fix **To Do:** New Request **In Progress:** Under Review, Pending Approval, Processing **Done:** Completed, Fulfilled **Canceled:** Withdrawn, Denied **To Do:** New Request **In Progress:** Scheduled, In Progress, Ordered **Done:** Completed **Canceled:** Canceled *** ## Editing and Deleting Statuses ### Edit a Status 1. Click the **...** menu on the status 2. Select **Edit** 3. Update name, category, or description 4. Save changes Changing a status category (e.g., from "In Progress" to "Done") will affect how those tickets are counted in reports and views. ### Delete a Status 1. Click the **...** menu on the status 2. Select **Delete** 3. Choose a replacement status for existing tickets 4. Confirm deletion You cannot delete the default status. Set a different default first, then delete. *** ## Related Learn how to change ticket status from list view, detail view, or chat Understand all ticket properties and configuration options # Syncing to Your Ticketing System Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/syncing Connect Serval to external ticketing tools like Jira, Zendesk, ServiceNow, and more Serval integrates with your existing ticketing systems to provide a unified view of all requests. Sync tickets bidirectionally to keep both systems up to date without manual data entry. *** ## Supported Integrations Sync issues, statuses, and comments between Serval and Jira Connect Zendesk tickets with Serval for AI-powered resolution Integrate Freshservice incidents and service requests Sync incidents and catalog items with ServiceNow Sync Salesforce Service Cloud Cases with Serval tickets Sync Linear issues for engineering-focused ticketing *** ## How Syncing Works When you connect an external ticketing system, Serval: 1. **Creates linked tickets** - Tickets created in Serval can automatically create corresponding tickets in your external system 2. **Syncs updates bidirectionally** - Status changes, comments, and assignments sync in real-time 3. **Maintains references** - Each ticket displays links to its counterpart in the external system Sync settings are configured per team. Each team can connect to different external systems or projects. *** ## Setting Up a Sync Navigate to **Settings** → **Integrations** and authenticate with your external ticketing system. See the integration-specific guide for setup details: [Jira](/sections/integrations/jira#ticket-syncing), [Freshservice](/sections/integrations/freshservice), [ServiceNow](/sections/integrations/servicenow), [Salesforce](/sections/integrations/salesforce#ticket-sync), [Linear](/sections/integrations/linear#ticket-syncing), [Zendesk](/sections/integrations/zendesk). In your team settings, select which external project or queue should receive tickets from this team. Configure how Serval fields map to your external system: | Serval Field | Maps To | | :- | :- | | Status | External status (configurable) | | Priority | External priority | | Assignee | External assignee (if user exists) | | Labels | Tags or labels | | Description | Description or body | The direction applies to new tickets only: * **Serval → External**: tickets created in Serval are sent to the external system. Tickets created externally aren't imported. * **External → Serval**: tickets created externally are imported into Serval. Tickets created in Serval aren't automatically sent out. * **Bidirectional**: tickets created in either system are synced to the other. **Updates to synced tickets sync both ways under every direction.** Changes made in Serval appear in the external system, and changes made in the external system appear in Serval. This covers comments and attributes (status, priority, assignment), as enabled by the Sync Scope toggles. At least one Sync Scope toggle must stay enabled on every source, so you can't make a connected sync fully read-only. Under **External → Serval**, a ticket created in Serval isn't automatically sent to the external system, but a change you make in Serval to a synced ticket does write back. There is no import-history-then-stop mode: **Historical + New** is a live, ongoing sync that begins with a backfill. For a one-time import with no live connection, use the team's CSV ticket import page instead. *** ## Jira routing workflows Jira ticket sources can use an optional routing workflow to choose the destination for a new Jira issue. The workflow selects a project from the source's configured projects and supplies its type and any required field values. Serval creates the issue and links it to the existing Serval ticket. * **Service Management**: return `projectId`, `requestTypeId`, and any `fields` needed by that request type. * **Project Management**: where PM project syncing is enabled, return `projectId`, `issueTypeId`, and any `fields` needed by that issue type. Subtask creation isn't supported. * **Use the default**: return `null` to keep the configured default destination. Field values are keyed by Jira field ID and must match the selected project and type. When routing to another destination, supply its required values; the default destination's field configuration doesn't automatically apply. The routing workflow chooses the destination and values without creating, updating, or linking Jira issues itself. Routing applies before the first Jira issue is created. Once a ticket is linked, updates continue to target that issue. ## Status mapping Status mapping controls how ticket statuses translate between Serval and the connected system. Configure it in the ticket source's **Status mapping** settings. Mappings are direction-aware, so incoming and outgoing changes can map differently: * **Incoming (external → Serval)**: the Serval status a synced ticket takes when its status changes in the external system. * **Outgoing (Serval → external)**: the external status Serval sets when the ticket's status changes in Serval. Outgoing status mapping is available for Jira, Zendesk, Freshservice, Linear, and ServiceNow. Configuring the outgoing direction is optional. If a Serval status has no explicit outgoing mapping, Serval falls back to the reverse of your incoming mappings when it pushes the status to the external system. For ServiceNow, the Status Mapping dialog shows one tab per synced record type — Requested Item, Incident, and HR Case — and both directions follow the selected tab. ServiceNow incidents are created in Serval as incident tickets, so the Incident tab maps ServiceNow incident states to Serval's incident statuses. Requested items and HR cases are created as requests and map to request statuses. A ticket's type is set when Serval first creates it; tickets synced earlier keep the type they already have. Serval can automatically map statuses by matching names across both directions. Start there, then adjust any statuses that don't line up one-to-one. *** ## Priority mapping Configure priority mapping in the ticket source settings to control how a ticket's priority translates between Serval and the connected system; your mappings are honored on every connector (Jira, Zendesk, Freshservice, Linear, Salesforce, ServiceNow). Outgoing, a priority with no mapping fails the sync rather than shipping a wrong default (a priority of **None** is never an error); incoming, Serval applies a matching mapping and otherwise leaves the priority unchanged. With no mappings configured, each system keeps its previous default behavior. *** ## Automatic Channel Sync on Ticket Transfers When a ticket is moved to a different team, all configured channels for the destination team automatically sync with that ticket. The ticket follows the new team's syncing configuration — so if the destination team syncs to Jira, the transferred ticket creates a corresponding Jira issue automatically. *** ## Sync Behavior ### Choose which attributes sync By default every field syncs, with **Sync attributes** turned on. To narrow that, open the ticket source's sync settings, expand **Choose which fields to sync**, and turn off the fields you don't want: **Status**, **Priority**, **Assignment**, **Title**, and **Description**. Turning **Sync attributes** off stops all field syncing at once. Comments sync independently, controlled by the separate **Sync comments** toggle. This applies to the native connectors: Jira, Zendesk, Freshservice, Linear, Salesforce, and ServiceNow. ### What Syncs Automatically New tickets sync based on your configured direction. The linked ticket is created within seconds. When a ticket status changes in either system, the corresponding status updates in the other. Status mapping is configurable. Public comments sync between systems. Internal notes remain private to each system. Assignee changes sync when the user exists in both systems. Files attached to messages sync with the ticket for Jira, Zendesk, Freshservice, Linear, ServiceNow, and Salesforce. Attachments on internal notes sync only where the connected system supports private attachments (Zendesk and Freshservice). Files larger than the connected system's size limit are skipped. ### What Doesn't Sync * Custom fields not mapped in configuration * Internal notes and private comments * The external system's own workflow automations (these run independently in each system) *** ## Running Workflows on Synced Tickets When a ticket syncs into Serval from a connected system, it becomes a regular Serval ticket and can drive Serval automation like a native ticket. This includes tickets escalated in ServiceNow or Freshservice. You can have Serval run a workflow in response: * **Event-triggered workflows**: build a workflow with an event trigger, such as *Ticket created*, so it runs automatically when a matching ticket arrives. See [workflow types](/sections/documentation/workflows/Configure/types#event-triggered-workflows). * **Escalation workflow**: a team can configure a workflow to run whenever a ticket escalates. This is Serval running its own automation on the synced ticket. It's separate from the external system's native automations, which run independently and don't carry over (see [What Doesn't Sync](#what-doesnt-sync)). *** ## Best Practices Ensure your status mappings reflect equivalent workflow stages in both systems Let Serval handle AI triage and routing, then sync resolved tickets to your system of record Validate your sync configuration with one team before rolling out organization-wide Check the integration status regularly to catch any sync failures early *** ## Troubleshooting * Verify the integration is connected in Settings → Integrations * Check that the team has sync enabled and a project/queue selected * Ensure the user creating tickets has permission to create in the external system * Review your status mapping configuration * Confirm the target status exists in the external system * Check for any workflow rules in the external system that might prevent the update * Ensure you're not creating tickets in both systems manually * Check that sync direction is configured correctly * Review any automation rules that might be creating tickets # Tasks Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/tasks Add tasks to tickets to manage complex processes. ## Overview You can add tasks to tickets to break complex tickets into smaller, actionable steps. Each task has the same properties as a standard ticket, but maintains a parent-child relationship with its parent ticket. ## Creating tasks You can create tasks in 3 ways: 1. Add a task to an existing ticket 2. Convert a ticket to a task 3. Automate task creation from workflows ### Option 1: Add a task to an existing ticket Open any ticket and create a new task directly within it. Navigate to **Tickets** → Select Ticket → Click the **"+"** sign next to Tasks → Add all the same information you would to a ticket (e.g., name, description, assignee) ### Option 2: Convert a ticket to a task You can convert any existing ticket into a task by assigning it a parent ticket. This is useful when you realize a ticket is actually part of a larger piece of work. Navigate to **Tickets** → Select Ticket → Click the three dots on the right corner → Select **"Set parent ticket"** → Search for parent ticket ### Option 3: Automate task creation Use workflows to automatically generate tasks. When creating a workflow, instruct Serval to create the subtasks you need. When the workflow is triggered, the tasks will automatically be created, and viewable in the ticket in app.serval.com. For example, create an onboarding workflow that automatically creates two tasks and assigns one to Spencer. When you onboard a new employee, the two tasks will automatically be created and assigned to the respective individuals. Go into the ticket in [app.serval.com](http://app.serval.com) to view the tasks. ## How tasks work Tasks operate like regular tickets with a few key differences: 1. **Tasks have parent tickets**: A task has a "child" relationship to a "parent" ticket. Tasks use a two-layer hierarchy — tasks cannot have their own sub-tasks. 2. **Manual or automated**: Each task can trigger its own workflows or be completed manually. Tasks don't need to follow the same workflow as their parent ticket. 3. **Cross-team assignment**: Assign tasks to any team member, regardless of your role in their team. This makes it easy to coordinate work across multiple teams. 4. **Parallel execution**: Multiple tasks can be active simultaneously. There's no limit to how many tasks a ticket can have. 5. **Visible on parent ticket**: All child tickets (tasks) are visible at the top of the parent ticket, including tasks created by workflows. This gives you a clear overview of all related work. ## Filtering tickets and tasks Use relation filters to find specific ticket types. Navigate to **Tickets** → **Filter** → **Relations** → Choose between: * **Parent tickets**: Tickets that have at least one task * **Child tickets**: All tasks (tickets with a parent) You can also use the **Type** filter to narrow by ticket type: * **Requests**: Root-level tickets (no parent) * **Tasks**: Tickets that are children of a parent request Ticket badges display full type names — "Request" and "Task" — for clarity. For example: * Filter for "Parent tickets" to see all major projects that have been broken down into smaller tasks * Filter for "Child tickets" assigned to you to see all the individual tasks you're responsible for, regardless of which parent ticket they belong to * Use the "Type" filter to quickly switch between viewing requests and tasks # Ticket Types Source: https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/ticket-types Understand the difference between requests, incidents, major incidents, changes, and problems Serval supports different ticket types to help you categorize and handle various kinds of support needs appropriately. *** ## Understanding Ticket Types A request for something new—access, equipment, information, or a service Something is broken or not working as expected and needs to be fixed A high-impact incident, such as a widespread outage, that needs an urgent, coordinated response A controlled modification to your environment that follows a governed lifecycle A root-cause investigation behind one or more incidents, tracked to a resolution ### Requests Requests represent asks for something the employee doesn't currently have: * **Access requests** - "I need access to Salesforce" * **Equipment requests** - "Can I get a second monitor?" * **Service requests** - "Please set up a new Slack channel for our team" * **Information requests** - "What's the policy on remote work?" Requests typically follow a fulfillment workflow: receive → approve (if needed) → provision → complete. ### Incidents Incidents represent issues that need to be fixed: * **System issues** - "Email is not syncing on my phone" * **Bugs** - "The dashboard is showing incorrect data" * **Outages** - "I can't access the VPN" * **Errors** - "I'm getting an error message when I try to submit" Incidents typically follow a resolution workflow: receive → diagnose → fix → verify → complete. ### Major Incidents Major incidents represent high-impact issues that affect many people at once: * **Widespread outages** - "The VPN is down for the whole company" * **Provider failures** - "No one can log in through Okta" * **Core app unavailable** - "Email is down for everyone" * **Critical degradation** - "The network is unusable across the office" As new reports come in, Serval links each related ticket on the same team to the existing major incident, rather than linking those tickets to one another, so everyone affected is tracked and updated together. Only team managers can create a major incident. Major Incident is enabled per team, so a team turns it on in Team Settings before major incidents can be created. For the full model, including AI-driven and manual linking and broadcasts, see [Incident Management](/sections/documentation/ticketing/incident-management). ### Changes Changes represent controlled modifications to your environment: * **Infrastructure changes** - "Deploy the new database cluster to production" * **Configuration changes** - "Update the firewall rules for the new office network" * **Hardware changes** - "Replace the UPS batteries in server room B" * **Software changes** - "Upgrade the CRM to version 4.2" Changes follow a governed lifecycle with assessment, authorization, implementation, and review stages. Each change is associated with a **change model** (Normal, Standard, or Emergency) that determines the required approvals and process gates. For full details, see [Change Management](/sections/documentation/ticketing/change-management). ### Problems Problems represent the investigation into the underlying cause behind one or more incidents: * **Recurring incidents** - "The VPN keeps dropping every afternoon—find out why" * **Root-cause analysis** - "Determine what caused last week's outage and how to prevent it" * **Known-error tracking** - "Document the workaround while we work on a permanent fix" Use a **Problem** when incidents are being restored but the underlying cause still needs to be found, summarized, and tracked. An owner is assigned the problem and decides what to do with it—whether to trigger a [Change](/sections/documentation/ticketing/change-management) to implement the permanent fix or raise a [Request](/sections/documentation/ticketing/ticket-configuration/ticket-types#requests) for a related service need. For full details, see [Problem Management](/sections/documentation/ticketing/problem-management). Incidents are about restoring service quickly; problems are about making sure the same issue doesn't come back. A single problem often sits behind several related incidents. ### Custom Types When none of the built-in types fit, your team can define its own **custom ticket type** — for example, Legal Intake, Onboarding, or Access Review. Each custom type has its own lifecycle, transitions, entry workflows, and custom fields. For full details, see [Custom Ticket Types](/sections/documentation/ticketing/ticket-configuration/custom-ticket-types). *** ## How Ticket Types Affect Handling | Aspect | Request | Incident | Major Incident | Change | Problem | | :- | :- | :- | :- | :- | :- | | **Goal** | Fulfill the ask | Restore normal operation | Coordinate response to a widespread outage | Implement a controlled modification | Find and eliminate a root cause | | **Urgency** | Based on business need | Based on impact and scope | High, team-wide impact | Based on change model (Normal/Standard/Emergency) | Based on recurrence and risk | | **Approval** | Often required | Rarely required | Rarely required | Required for Normal and Emergency changes | Not required | | **SLA** | Fulfillment time | Resolution time | Resolution time | Implementation window | Investigation time | | **Metrics** | Time to fulfill | Time to resolve, MTTR | Time to resolve, MTTR | Lifecycle progression, approval time | Time to identify root cause | | **Who can create** | Anyone | Anyone | Team managers | Team managers | Team managers | These types connect to each other — an incident can log a problem, a problem can drive a change, and so on. To create one ticket type from another with AI-assisted prefill, see [Ticket Flows](/sections/documentation/ticketing/ticket-flows). *** ## AI Classification Serval's AI automatically classifies incoming tickets as requests or incidents based on the message content. The AI looks for signals like: * **Request signals** - "I need", "Can I get", "Please set up", "Requesting" * **Incident signals** - "Not working", "Error", "Broken", "Can't access", "Issue with" *** ## Configuring Ticket Types ### Enable/Disable Types You can choose which types appear on your team's Ticket Types page. You need permission to update ticket models. 1. Go to **Team Settings** → **Capabilities**. 2. Find the **Ticketing** section. You can also reach it through **Manage ticket types** on the Ticket Types page. 3. Turn optional types on or off. Changes save automatically, and enabled types appear on the Ticket Types page. 4. Select an enabled type's name to edit its settings. Custom types are configured from **Team Settings** → **Ticket Types** → **Custom**, rather than from Capabilities. Requests and tasks are always enabled. Configure them on the **Ticket Types** page; they do not appear as toggles in Capabilities. You can't turn off Incident, Major Incident, Change, or Problem while the type still has tickets that haven't been permanently deleted. Completed, archived, and Recently Deleted tickets also count. You also can't turn off a type that still has tickets synced from a connected external system (Jira, ServiceNow, Zendesk, Freshservice, Salesforce, or Linear), because disabling it would break those synced tickets. Turning off Journey instead turns off your team's Journey capability. Enabling Change or Major Incident doesn't install its models or workflows. Select the type's name to complete the existing setup for that type. Turning a type off preserves its configuration. ### Type-Specific Settings Configure different behaviors for each ticket type: Create type-specific statuses: * Requests: "Pending Approval", "Provisioning", "Fulfilled" * Incidents: "Investigating", "Identified", "Monitoring", "Resolved" Set different response and resolution times: * High-priority incidents may have 1-hour SLA * High-priority requests may have 24-hour SLA Route types to different assignees: * Requests → General IT team * Incidents → Senior IT operations team *** ## Best Practices For most teams, just Request and Incident are sufficient. Add more types only if you have distinct handling needs. If you sync with an external system, align your ticket types with their categories. # Ticket Flows Source: https://docs.serval.com/sections/documentation/ticketing/ticket-flows Track a resolution as it moves across ticket types — creating a new incident, problem, or change from an existing ticket, with AI-assisted field prefill and automatic linking Resolving an issue often spans more than one ticket. An incident can reveal an underlying problem, a problem can call for a change to fix it permanently, and a request can turn out to be an incident. Serval models these connections directly: you can **derive** a new ticket of a different type from an existing one. Deriving doesn't convert the original ticket — it creates a separate new ticket, pre-fills it from the source, and links the two together so the related work stays connected. Diagram of Serval ticket types: requests can raise incidents, incidents log problems, problems drive changes or expand back into requests, incidents can trigger emergency changes, and a proactive automation layer drafts remediations across all types *** ## How Tickets Flow Across Types Each ticket type has a distinct job, and work on one ticket often leads to opening a related ticket of a different type: * An **Incident** can be promoted to a **Major Incident** when it turns out to be widespread or business-critical and needs an accelerated, coordinated response (see [Incident management](/sections/documentation/ticketing/incident-management)). * An **Incident or Major Incident** can uncover an underlying **Problem** when service is being restored but the root cause still needs to be found. * A **Problem** can lead to a **Change** when the permanent fix requires a controlled modification, or to a **Request** when it surfaces a new service need. * An **Incident or Major Incident** can call for a **Change** directly — for example, an emergency change to resolve an active outage. * A **Request** can turn out to be an **Incident** when what looked like an ask is actually something broken. Above these records, a proactive automation layer — driven by [background agents](/sections/documentation/catalyst/agents) — runs analysis, reports findings, and drafts remediations (workflows, knowledge articles, and agent skills) that apply across every ticket type. *** ## Deriving a Ticket from Another Ticket **Deriving** creates a brand-new ticket of a different type from an existing ticket. It's different from reclassifying a ticket in place: the original ticket stays as-is, a new ticket is created, and the two are linked. ### Supported Derivations Serval only allows derivations that make sense as work progresses. Deriving is one-directional — it goes from a source type to a target type. | From this ticket | You can derive | Typical reason | | :- | :- | :- | | **Request** | Incident | The ask turned out to be a service disruption | | **Incident** | Problem, Change | Log the underlying problem, or make an emergency change to fix it | | **Major Incident** | Problem, Change | Investigate the root cause, or make an emergency change to restore service for a widespread outage | | **Problem** | Request, Change | Raise a related service request, or implement the permanent fix | Turning an incident into a major incident is an in-place promotion, not a derivation, so it isn't in the table above. See [Incident management](/sections/documentation/ticketing/incident-management). **Change** tickets are a destination only — you can derive a change from an incident, major incident, or problem, but you can't derive another ticket type from a change. ### How to Derive From the ticket you want to derive from, open the ticket actions menu and select **Derive ticket…**. Serval defaults the new ticket to the most relevant target type for that source (for example, an incident defaults to deriving a **Problem**). Pick which type of ticket to create from the allowed targets for that source. You can also start from the **Create Ticket** dialog and pick a source ticket there instead. Serval uses AI to draft the new ticket's fields from the source ticket. Review and edit anything before submitting. The new ticket is created and automatically linked to the source ticket. Deriving a ticket is a team-manager action. The source ticket and the new ticket must belong to the same team, and you can't derive from an archived ticket. ### What Gets Pre-Filled When you derive a ticket, Serval reads the source ticket — including its full message thread and custom field values — and uses AI to draft the new ticket's: * **Title** and **description** * **Status** and **priority** * **Labels** * **Custom fields** that map to the target ticket type Serval **rewrites** the title and description for the destination type rather than copying them verbatim — a derived **Problem** is framed as the underlying root cause, while a derived **Change** is framed as the modification to make. Everything is a starting point you can edit before submitting. Requester, due date, and assignee aren't carried over — the new ticket starts fresh. When deriving a **Change**, you also choose the change model and can attach the configuration items the change affects. ### Records Are Linked Automatically You never have to link a derived ticket by hand. When a derived ticket is created, Serval automatically links the new ticket to its source and logs the link on the ticket's timeline. The link is bidirectional: both tickets show each other under **Linked Tickets** in the ticket sidepanel, so you can move between the incident, the problem it uncovered, and the change that resolved it. This is the same linking used when you manually link two existing tickets — deriving simply creates the link for you as part of creating the new ticket. To remove a link, open the **Linked Tickets** section and select the unlink control (the **X**) on the linked ticket. This needs permission to update the ticket and isn't available on archived or read-only tickets. The change is logged on both tickets' timelines. *** ## Automating Ticket Creation and Linking Deriving is the manual way to move work between ticket types. You can also automate it: build a workflow that creates a ticket — of any type, including a **Problem** — and links it back to the ticket that triggered the workflow, with no manual step. Because workflows can run in response to ticket events (such as an incident being created, escalated, or labeled) and evaluate the ticket's content and fields, you can encode your own auto-detection of when a new ticket is warranted. For example, when an incident matches the conditions your team associates with a deeper issue, a workflow can automatically open a linked **Problem** from it — so the relationship is captured every time your criteria are met, without anyone deriving it by hand. You build these automations in [Catalyst](/sections/documentation/catalyst/overview) using natural language, and choose the ticket type to create and the link to establish. See [Workflows](/sections/documentation/workflows/overview). Use manual deriving for one-off cases where a person decides a new ticket is needed. Use a workflow when you want the same create-and-link to happen automatically, every time your conditions are met. *** ## Related Pages * [Ticket Types](/sections/documentation/ticketing/ticket-configuration/ticket-types) * [Incident Management](/sections/documentation/ticketing/incident-management) * [Problem Management](/sections/documentation/ticketing/problem-management) * [Change Management](/sections/documentation/ticketing/change-management) * [Workflows](/sections/documentation/workflows/overview) * [Assignment & Routing](/sections/documentation/ticketing/manage-collaborate/assignment-routing) # Auditing Workflows Source: https://docs.serval.com/sections/documentation/workflows/Audit/review-workflows Track workflow activity for compliance, reporting, and analysis Serval provides multiple ways to audit workflow activity directly through the UI or through workflows. *** ## Example Audit Workflows Create these workflows by pasting the prompt into Catalyst. ### Weekly Workflow Audit Report Generate a CSV report of all workflow runs with detailed metadata. **Prompt:** > Create a scheduled workflow that runs every Monday at 9am. It should list all workflows in the team, get the run history for each workflow from the past 7 days, and generate a CSV report with columns for workflow name, workflow ID, run ID, status, started at, completed at, triggered by, and duration. Post the report to #it-ops in Slack with a summary of total workflows, total runs, successful runs, and failed runs. *** ### Daily Run Summary Get a daily digest of workflow activity. **Prompt:** > Create a scheduled workflow that runs every day at 9am. Get all workflow runs from the past 24 hours and post a summary to #it-ops in Slack showing the count of successful, failed, and pending approval runs. *** ### Monthly Workflow Usage Report Track which workflows are used most frequently. **Prompt:** > Create a scheduled workflow that runs on the first of every month at 9am. List all workflows, count how many times each was run in the past 30 days, calculate the success rate for each, and post the top 10 most-used workflows to #it-ops in Slack. *** ### Access Change Audit Track all access provisioning and deprovisioning activity. **Prompt:** > Create a scheduled workflow that runs every Friday at 5pm. Get all workflow runs from access provisioning and deprovisioning workflows in the past week. Generate a CSV with user email, application, action (granted/revoked), approver, and timestamp. Post to #security in Slack. *** ### Approval Turnaround Report Monitor how quickly approvals are being processed. **Prompt:** > Create a scheduled workflow that runs every Monday at 9am. Find all workflow runs from the past week that required approval. Calculate the average time between when approval was requested and when it was approved or denied. Post a summary to #it-ops in Slack with the average approval time and list any approvals that took longer than 24 hours. *** ## Compliance Use Cases Generate evidence of access changes with timestamps and approvers Track all workflow modifications with version history Audit which workflows granted or revoked access Review workflow activity during security investigations *** ## Best Practices Create scheduled workflows that generate weekly or monthly audit reports Set up immediate notifications for workflow failures Pay extra attention to workflows that modify access or sensitive data Store audit exports in your organization's document management system # Approvals Source: https://docs.serval.com/sections/documentation/workflows/Configure/approvals Serval workflows can require approvals before or during execution, adding a layer of control for sensitive operations. Approvals are built as an ordered sequence of steps, and each step asks one or more approvers at once. ## Overview An approval procedure is a sequence of **steps**. Each step is sent to one or more approvers, and you decide per step whether **all must approve** or **any one can approve**. Within a step, an approver can be: * **A specific user** * **A group**, optionally with a quorum, such as "4 of 8 must approve" * **The requester's manager** * **A custom approval workflow** that decides automatically based on your own logic, or escalates The same builder powers both workflow approvals and [access-policy approvals](/sections/access-management/configuration/access-policies). The workflow approval procedure dialog showing approval steps and their approvers ## Add approvals to a workflow Approvals appear as a **Get approvals** step in the workflow. On a new workflow (on-demand or form-submit triggers), click **Add Approvers** above the workflow to create the first step. Once steps exist, the **Get approvals** node summarizes its approvers, and selecting it reopens the builder. Both open the **Workflow approval procedure** dialog, where you configure who approves the workflow, step by step. A workflow with a Get approvals step showing its approver summary and Configure button ### Build the steps 1. Click **Add approval step** and pick the approvers for that step. A single step can mix several approvers: specific users, groups, and the requester's manager. 2. If a step has more than one approver, choose **All must approve** or **Any one can approve**. 3. For a group with two or more members, set a quorum: the number of members who must approve. The step then reads as **N of M must approve**. 4. Add more steps for sequential approval. Steps run in order, and each begins only after the previous one completes. A workflow approval procedure with multiple steps configured ### Notified vs. backup approvers Each approver in a step is either **notified** or **backup**: * **Notified** approvers are alerted when the step is pending and count toward satisfying it. * **Backup** approvers aren't notified but can still step in and approve. Every step needs at least one notified approver. On an **All must approve** step, every approver is required, so they're all notified. ### Remind pending approvers After an approver has been waiting for 24 hours, anyone who can reply to the request’s ticket can select **Remind** on the approval card. People with override permission also see **Override**. Outside a ticket, reminding requires override permission. Serval posts a short reply beneath the approver's original Slack approval message. The original approval buttons continue to work. This action currently supports Slack only. Reminders respect approval notification preferences and only reach approvers who are still waiting to decide. After a reminder is sent, the request has a shared 24-hour cooldown and the sender is recorded in the audit log. If no original Slack approval messages are available, a toast explains this and you can retry without waiting a day. ### Approver justification Approvers can be asked to record a note when they decide. Set **Approver justification** to **None**, **Optional**, **Required**, **Required to approve**, or **Required to deny**. The approver enters the note when they approve or deny, and it's captured wherever they act (Slack, Microsoft Teams, and the Serval inbox) and stored with the decision. ### Self-approval Control whether an approver can approve their own request. Toggle it per approver, or set **Allow all approvers to self approve?** for the whole procedure. When a step has a single approver, self-approval stays on so a request they submit isn't left stuck. ## Mid-run approvals A workflow can pause partway through to collect an approval, rather than only gating before it starts. When the workflow reaches a **Get approvals** step, it holds until an approver responds, then resumes automatically. If an approver denies the request, the workflow stops. * **Approve at the right moment**: Run initial steps first, then request approval only when the workflow reaches a decision point. * **Respond anywhere**: Approvers respond in Slack, Teams, email, or the Serval web portal, and the request appears in their inbox. * **Choose who approves**: Route to a specific user, a group, or the requester's manager, and chain multiple approval steps together. Use this when one workflow needs a human decision at a specific point without splitting the logic across separate workflows. Common examples include mid-run approvals for budget sign-offs, access escalations, and security reviews. ## Delegation Approvers can delegate their approval authority to another user or group, so requests keep moving when an approver is out. Delegation covers workflow approvals, access-request approvals, and ticket assignments. * **Set rules in user settings**: Configure delegation from a user's settings, not a workflow's approver dialog. Each rule names the delegator and one or more delegates. * **Delegate to a user or a group**: Route delegated approvals to a specific person or to any member of a group. * **Route automatically**: When an approval would go to the delegator, Serval sends it to the delegate instead, with no manual reassignment. * **Also applies to ticket assignments**: When a ticket would be assigned to the delegator, Serval routes it to their delegate instead. * **New approvals and assignments only**: A delegation **rule** applies only to approvals and assignments that start after the rule is active. Anything already assigned to the delegator stays with them. * **Set an active window to the hour**: A rule's start and end include a time of day, not just a date, and display in each viewer's time zone. A rule past its end shows an **Expired** badge and stays editable. * **Keep a clear audit trail**: The approval timeline shows who delegated and who made the final decision. * **Manage through the API**: Create and manage delegation rules with the Serval public API. Delegation rules route approvals to someone you choose in advance. To unblock a request in the moment, a role with the [Override approvals](/sections/documentation/platform/permissions#custom-team-roles) permission can approve or deny the current step of any of the team's approval requests without being an assigned approver. Every override is recorded in the audit log. ### Delegating a single request If your team has this turned on, a pending approver can hand their seat on one request to another person. That person's approval counts as the original seat. You do this from the web approval actions on the ticket, workflow run, or inbox row, not from Slack, Teams, or email. * **Pick one person**: The delegate must be an active user in your organization. You can't pick yourself, someone who already has a seat on the step, or the person the request is for, even when self-approval is on. Someone who submitted the request on another person's behalf isn't excluded for that reason alone. * **Custom approval workflows**: You can't delegate a step configured to use a custom approval workflow, including when that workflow selects human approvers. Ordinary inline approval steps inside the workflow can still be delegated. * **Approval authority transfers**: After you delegate, you can no longer approve or deny that seat. The delegate can approve, deny, or hand the seat on. * **Notifications follow the seat**: Your pending approval notification updates to delegated. The delegate gets a new approval request. Email already sent to you isn't retracted. Its links can't record a decision unless you hold a current seat on that step. * **Audit trail**: The approval timeline still shows who the seat started with and who you handed it to. ## Best practices * **Use groups with a quorum for scalability**: Instead of listing individual users, add a group and set how many of its members must approve, so approval keeps working as the team changes. * **Pick the right step rule**: Use **Any one can approve** when any qualified person can sign off, and **All must approve** when every named approver is required. * **Use manager approval for hierarchical sign-off**: Add the requester's manager as an approver when a request needs a reporting-line decision. * **Add backup approvers for coverage**: Include backup approvers on a step so someone can still act when the notified approver is unavailable. * **Require justification for sensitive steps**: Set approver justification to **Required** on high-impact steps to capture why each decision was made. * **Review self-approval carefully**: Decide whether approvers should be able to approve their own requests based on your security requirements. When a single user is the only approver on a step, keep self-approval on so a request they submit isn't left stuck. # Workflow Configuration Source: https://docs.serval.com/sections/documentation/workflows/Configure/build-guide Configure workflow behavior, approvals, inputs, and execution scope After creating a workflow, configure how it runs, who can run it, and what information it needs. This guide provides an overview of all configuration options. ## 1. Create a Workflow To get started with automations, build a workflow from scratch in Catalyst, install a pre-built workflow, or duplicate an existing one. Build a workflow from scratch in Catalyst using natural language Select a pre-built workflow to start with and configure as needed If there's another Team in Serval already set up, you can duplicate workflows across teams ## 2. Configure the Workflow Once you've created a workflow, you can configure that workflow with the following specifications to meet your organization's needs. Choose the right type: help desk, team-only, scheduled, webhook, event-triggered, or access workflows Configure when workflows run: manually, on schedule, via webhook, or on events Require approval before execution using static approvers or custom approval workflows Collect information from users: text, dropdowns, dates, and more. Workflows with form inputs automatically appear as catalog items. Control who can run the workflow: anyone in the org or team members only Track changes and restore previous versions of your workflows *** ## Quick Reference | Setting | What it controls | Options | | :- | :- | :- | | **Type** | Who can trigger and how | Help desk, team-only, scheduled, webhook, event-triggered | | **Trigger** | When the workflow runs | Manual, scheduled, webhook, event-based | | **Approvals** | Who must approve before execution | None, specific users, groups (with an optional quorum), manager, custom workflow | | **Inputs** | What information users provide | Text, textarea, number, date, time, select, checkbox | | **Execution scope** | Who can run the workflow | Anyone in org, team members only | *** ## Common Configurations ### Self-Service Help Desk Workflow For workflows that help desk users can trigger: | Setting | Configuration | | :- | :- | | Type | Help desk | | Execution scope | Anyone in the org | | Approvals | None (or manager approval for sensitive actions) | | Inputs | Minimal—agent collects info conversationally | ### Internal Team Workflow For workflows restricted to your team: | Setting | Configuration | | :- | :- | | Type | Team-only | | Execution scope | Team members | | Approvals | Optional | | Inputs | As needed for the operation | ### Automated Report For scheduled reports and notifications: | Setting | Configuration | | :- | :- | | Type | Scheduled | | Trigger | Weekly Monday 9am PST | | Approvals | None | | Inputs | None (or defaults configured) | ### Sensitive Operation For workflows that need oversight: | Setting | Configuration | | :- | :- | | Type | Help desk or team-only | | Approvals | Manager approval or multi-step approval chain | | Inputs | Justification text area, confirmation checkbox | *** ## Child Workflows A child workflow is a workflow that the parent workflow calls as a step in its own process. Build a piece of logic once, then reuse it across any number of parent workflows instead of rebuilding it each time. Use child workflows to keep shared logic in a single source of truth. Common use cases include: * Shared onboarding and offboarding steps that several team workflows depend on * Centralized approval flows reused across any workflow that needs approval * Standard escalation routines that multiple teams run the same way When you describe a parent workflow calling a child, Catalyst reads the child's input fields and types, then wires up the call with the right parameters. If a child workflow requires approval, that approval surfaces on the parent workflow's ticket and sends a Slack notification, so a pending child never stalls the parent silently. Serval links child runs to the parent run, so the tree in run history shows the entire, combined process. ## Send WhatsApp notifications Connect your Twilio account on the team that owns the workflow. Create and manage notification templates in that account's Content Template Builder. For business-initiated messages outside the customer service window, use [approved WhatsApp templates](https://www.twilio.com/docs/whatsapp/tutorial/send-whatsapp-notification-messages-templates). Call `twilio.common.sendWhatsAppMessage` with the workflow's Twilio context: ```typescript theme={null} await twilio.common.sendWhatsAppMessage({ fromPhoneNumber: "+15551234567", toPhoneNumber: employeePhoneNumber, contentSid: "HX0123456789abcdef0123456789abcdef", variables: { "1": employeeName, "2": `https://app.serval.com/journeys/${journeyId}?org=${organizationSlug}`, }, }, ctx); ``` | Field | Value | | - | - | | `fromPhoneNumber` | Your registered WhatsApp sender in E.164 format, including `+`. | | `toPhoneNumber` | The recipient's WhatsApp phone number in E.164 format. | | `contentSid` | The approved template's Content SID from the connected Twilio account. | | `variables` | Every variable required by your selected template, keyed by its placeholder number. Omit for templates without variables. | The action returns `messageSid` and `status`. It sends WhatsApp only. To notify everyone by both channels, call the existing email action as well, and use each recipient's phone for the WhatsApp action. Users without a phone can still receive email. Handle failures independently so one channel's failure doesn't skip the other. For an initial invitation, send the ordinary Journey URL. Opening it takes the recipient through sign-in if necessary. The action doesn't generate authentication tokens, create a Serval inbox entry, or automatically run when a Journey is created. Schedule reminders and check whether tasks remain incomplete in your workflow. For other Twilio API calls, use `twilio.apiRequest` with `body` for JSON requests or `form` for form-encoded fields (`Record`). Supply only one of these options. Both use the connected Twilio account and return the parsed JSON response. # Team Only vs. Anyone in Organization Workflows Source: https://docs.serval.com/sections/documentation/workflows/Configure/execution-scope Choosing between team-only and organization-wide workflows, and understanding their relationship to Slack channel modes When building workflows in Serval, one of the most important decisions is determining who can trigger and access your workflow. This guide explains the two visibility options and how they integrate with your Slack channels. ## Overview Every Serval workflow has an **execution scope** that determines who can run it: Workflows available to all users across your organization. Ideal for self-service support and help desk automation. Workflows restricted to your team. Ideal for internal operations and sensitive automations. ## Understanding the Two Visibility Options ### Anyone in Organization Workflows set to **Anyone in the org** are available to all users in your Serval organization. These workflows are: * **Discoverable** by the Serval help desk agent when handling requests from any user * **Triggerable** from Help Desk or Silent Mode channels * **Visible** to users requesting help via DMs, `/serval help` command, or help desk channels * **Designed** for common support scenarios that benefit all employees **Example use cases:** * Password reset assistance * Software access requests * IT equipment troubleshooting * General onboarding tasks * Standard service requests Organization-wide workflows are the default choice for help desk automation. When a user asks for help in any channel, Serval can automatically suggest and run these workflows to resolve their request. ### Team Members Only Workflows set to **Team members** are restricted to members of your specific Serval team. These workflows are: * **Only available** to team members and Serval agents in Team Only Mode channels * **Hidden** from users outside your team * **Designed** for internal team operations or sensitive actions * **Protected** from accidental execution by unauthorized users **Example use cases:** * Internal team reporting and analytics * Sensitive data operations * Administrative tasks * Cleanup and maintenance operations * Team-specific integrations Team-only workflows are not triggered by the help desk agent in standard Help Desk or Silent Mode channels. They require a Team Only Mode channel or direct team member access. ## How Visibility Connects to Slack Channels Your workflow visibility setting directly determines which Slack channel modes can trigger those workflows. | Channel Mode | Organization Workflows | Team-Only Workflows | | - | - | - | | Help Desk Mode | ✅ Triggered by help desk agent | ❌ Not available | | Silent Mode | ✅ Triggered when @Serval mentioned | ❌ Not available | | Team Only Mode | ✅ Available | ✅ Available | | Team Inbox | ❌ Egress only (no new tickets) | ❌ Egress only (no new tickets) | | Disabled | ❌ No activity | ❌ No activity | ### Help Desk Mode and Silent Mode Channels These channels serve end users across your organization. When Serval processes a request in these channels, it only has access to workflows marked **Anyone in the org**. * The help desk agent evaluates incoming requests * If a matching organization-wide workflow exists, Serval triggers it automatically * Team-only workflows are never executed in these channels ### Team Only Mode Channels Team Only Mode channels are designed exclusively for your team members. In these channels: * Serval has access to **all** team workflows, including team-only workflows * The AI helps resolve requests but does not escalate to a human * Both organization-wide and team-only workflows can be triggered * Ideal for internal team channels like `#it-internal` or `#devops-team` Team Only Mode channels should only include members of your Serval team, as anyone with access to the channel can trigger team-only workflows. ## Setting Workflow Visibility ### When Creating a New Workflow New workflows default to **Anyone in the org**. Catalyst doesn't infer the scope from your description, so set it explicitly if the workflow should be restricted to your team. Workflow builder showing visibility scope selection ### After Workflow Creation You can change the visibility at any time: Navigate to **Workflows** and select the workflow you want to modify. On the workflow's **Trigger** node, find the **Request made by** dropdown. It shows either **Anyone in the org** or **Team members**. Choose the appropriate option from the dropdown. The change takes effect immediately for future workflow runs. ## Best Practices If a workflow helps users resolve common issues, make it available to the entire organization. This enables Serval to automatically assist users without requiring escalation. Workflows that modify critical systems, access sensitive data, or perform administrative actions should be restricted to team members. This provides an extra layer of protection. Configure your Slack channels to match your workflow strategy: * Use **Help Desk Mode** for user-facing channels where organization-wide workflows should run * Use **Team Only Mode** for internal team channels where you need access to all workflows Even organization-wide workflows can include approval steps. If a workflow performs sensitive actions, consider adding an approval requirement so a manager or team member must authorize execution before it runs. When building a new workflow, pause to consider: "Should anyone in the organization be able to trigger this?" If the answer is no, set it to team-only. ## Common Scenarios ### Scenario 1: Password Reset Workflow A workflow that helps users reset their password should be **Anyone in the org**: * Any employee might need password help * No sensitive administrative access required * Triggered via DMs, `/serval help`, or help desk channels Consider adding an optional approval step if you want a manager or IT team member to authorize the reset before it executes. This is useful for high-security accounts or when you want an audit trail of who approved the action. ### Scenario 2: User Account Cleanup Workflow A workflow that deactivates accounts and removes data should be **Team members**: * Only IT admins should trigger this * Sensitive operation with irreversible effects * Run from Team Only Mode channels or directly by team members ### Scenario 3: Daily Ticket Summary Workflow A scheduled workflow that summarizes open tickets should typically be **Team members**: * Internal team operations and reporting * Contains information that may not be appropriate for all users * Could be organization-wide if the summary is designed for broader visibility ## Related Documentation * [Slack Integration](/sections/integrations/slack) - Configure Slack channels and modes * [Create Your First Workflow](/sections/documentation/workflows/create-your-first-workflow) - Workflow creation guide * [Comprehensive Guide to Slack](/sections/documentation/helpdesk/interacting-with-serval-in-slack) - All Slack interaction methods # Workflow Inputs Source: https://docs.serval.com/sections/documentation/workflows/Configure/inputs Configure inputs and forms for workflows ## What Are Workflow Inputs? When a workflow needs information to run - like a username, date, or selection from a list - you define inputs. Users provide these values before the workflow executes. Any workflow with form inputs automatically appears as a catalog item in the **Catalog**. Users can browse these items by clicking **New Request** → **Browse Catalog** → **All Services** and submit structured requests directly from the catalog. See [Catalog](/sections/access-management/overview#for-end-users) for more details. **Example:** A "Create User" workflow might have inputs for: * Email address (text) * Department (dropdown) * Start date (date) * Is contractor (checkbox) ## How To Collect Inputs? Collect inputs via a form, including fields that appear only when relevant Collect inputs from the user via conversation *** ## Input Types Serval supports several input types: | Type | Description | Example Use | | :- | :- | :- | | **Text** | Single-line text entry | Username, email, ID | | **Textarea** | Multi-line text entry | Description, justification, notes | | **Number** | Numeric value | Duration, count, amount | | **Date** | Date picker | Start date, deadline | | **Time** | Time selector | Meeting time, schedule | | **Select** | Dropdown with options | Environment, role, department | | **Checkbox** | Boolean toggle | Enable flag, confirm action | | **Entity reference** | Searchable dropdown of records from an assets table | Cost center, location, application | *** ## Configuring Inputs When building a workflow, Serval automatically detects inputs based on your description. You can instruct Serval to change the inputs needed: When Serval generates your workflow, it identifies required parameters as inputs Change input types if needed: * Convert text to dropdown for constrained choices * Change text to textarea for long-form input * Add date/time pickers for temporal values Describe branching logic in plain language so fields show or hide based on earlier answers on the web app, in Slack, and on hosted forms (for Teams and email campaigns). Mark inputs as required or optional: * **Required** - User must provide a value * **Optional** - User can leave blank (workflow uses default or skips) Write clear descriptions for each input to guide users *** ## Target User Some workflows act on a specific person: resetting their password, ordering their laptop, suspending their account. Those workflows take a **Target User** instead of an email or user-ID input. Serval fills it in from the run, so the requester picks a person rather than typing an address, and the same workflow works whether someone runs it on themselves or on a colleague's behalf. A Target User shows up as a yellow **Target User** badge on the workflow's input step, and as a person picker on the run form. ### Describe who the target user is Say who the target user is for your workflow, in one sentence and from the requester's point of view. Open **Configure workflow inputs** on the input step and fill in **Who is the target user?** — for example, "The employee receiving the replacement laptop". That sentence appears in three places: * Under the person picker on the run form and in the Service Catalog, so the requester knows who to choose. * In the workflow builder, on the Target User badge. * In the help desk agent's description of the workflow, so it can tell whether someone named in a ticket is the right person to act on. Leaving it blank is allowed. Those surfaces then fall back to generic wording that reads the same on every workflow with a target user, so the requester has to infer who is meant. Write who, not what. "The employee receiving the replacement laptop" helps a requester; "the user this workflow runs for" repeats what the field already says. *** ## Form Confirmation For sensitive workflows, enable form confirmation to require users to review their inputs before execution: Turn on "Require form confirmation" in workflow settings User completes all input fields User sees a summary of all inputs and must confirm Workflow runs only after explicit confirmation Form confirmation adds an extra step but helps prevent accidental execution with incorrect values. *** ## Breakdown: Input Type Options ### Text input Single-line text for short values. **Best for:** * Usernames and email addresses * IDs and identifiers * Short strings **Configuration:** * Set placeholder text for guidance * Add description explaining expected format ### Textarea Multi-line text for longer content. **Best for:** * Descriptions and notes * Business justifications * Comments and feedback **Configuration:** * Consider setting a character limit if needed * Provide example text in the description ### Number Numeric input with validation. **Best for:** * Counts and quantities * Duration (days, hours) * Amounts **Configuration:** * Set min/max values if applicable * Specify units in the description (e.g., "Duration in days") ### Date Calendar date picker. **Best for:** * Start and end dates * Deadlines * Scheduled dates **Configuration:** * Consider default values (today, tomorrow, next week) * Specify date format expectations in description ### Time Time selection. **Best for:** * Meeting times * Schedule times * Time-specific events **Configuration:** * Clarify timezone expectations * Offer common presets if applicable ### Select (Dropdown) Choose from predefined options. **Best for:** * Environment selection (prod/staging/dev) * Role or permission level * Department or team * Any constrained set of choices **Configuration:** * Define all available options * Set a default selection if appropriate * Order options logically Use dropdowns instead of text inputs when you have a known set of valid values. This prevents typos and ensures consistency. ### Checkbox Boolean true/false toggle. **Best for:** * Feature flags * Confirmation checkboxes * Optional features **Configuration:** * Set clear label describing what the toggle controls * Consider default state (checked or unchecked) ### Entity reference A searchable dropdown backed by a [Serval assets table](/sections/documentation/databases/schema-design), so the requester picks a real record instead of typing free text. New records appear automatically, so the options stay current without manual updates. In the workflow builder, this input currently appears as **Item ref** (or **Item ref (multi)**). To configure the entity reference, follow these steps: 1. Select the assets table (entity type) the options come from. * Optionally, set which field shows as the label and which value the workflow receives * Optionally, show a field with a non-empty text value as secondary option text in the Serval app and Slack. Slack truncates it after 75 characters, and it doesn't change the value the workflow receives. * Optionally, filter which records appear, or restrict options to the current recipient 2. Use **Entity reference** to let the requester pick one record, or **Entity reference list** to let them pick several. ### Document signature Enable **Document Signing** under **Settings → Capabilities** and upload your PDF or Word template under **Settings → Document Templates**. You don't need a separate PandaDoc app instance. Turning the capability off later hides the **Document Templates** tab; your templates are kept and come back when you turn it on again. Ask Catalyst to use the template in a workflow; it can inspect the template's recipient roles, variables, and fillable fields before configuring the signature input. Turn on **Require form confirmation** for workflows with signature inputs. Attach the workflow to a ticket or task for the person who needs to sign. The requester opens its web form, signs the document, and submits the form to run the workflow. Other viewers see **Awaiting signature from another user…**. Catalyst's chat run form can't collect a signature because it has no ticket or task requester. Starting a workflow without opening its form doesn't create a document to sign. To test a signing workflow, open it from a ticket or task as its requester. *** ## Input Validation Serval validates inputs before workflow execution: * **Required fields** - Must be filled before submission * **Type validation** - Numbers must be numeric, dates must be valid * **Format validation** - Email fields check for valid email format ### Handling validation errors When validation fails: 1. User sees an error message on the invalid field 2. Workflow does not execute 3. User corrects the value and resubmits *** ## Examples ### User provisioning workflow | Input | Type | Required | Description | | :- | :- | :- | :- | | Email | Text | Yes | New user's email address | | First name | Text | Yes | User's first name | | Last name | Text | Yes | User's last name | | Department | Select | Yes | Engineering, Sales, Marketing, etc. | | Start date | Date | Yes | When the user starts | | Manager email | Text | Yes | Direct manager's email | | Is contractor | Checkbox | No | Check if temporary/contractor | ### Report generation workflow | Input | Type | Required | Description | | :- | :- | :- | :- | | Report type | Select | Yes | Daily summary, Weekly rollup, Custom | | Start date | Date | Yes | Report period start | | End date | Date | Yes | Report period end | | Include charts | Checkbox | No | Include visual charts in report | | Slack channel | Text | No | Channel to post report (blank = DM) | # Installable Workflows Source: https://docs.serval.com/sections/documentation/workflows/Configure/installable Pre-built workflows you can install and customize for your connected applications Installable workflows are pre-built automations for your connected applications. Instead of building common workflows from scratch, install a ready-made workflow and customize it for your needs. ## How It Works 1. **Connect an application**: Installable workflows appear after you connect an integration 2. **Browse available workflows**: See what's available for each connected app 3. **Stage for review**: Prepare unpublished workflow drafts in a Catalyst change set 4. **Review and publish**: Check the drafts and publish the change set to activate the workflows and their triggers 5. **Customize as needed**: Adjust inputs, approvals, and logic for your use case *** ## Finding Installable Workflows ### From Catalyst When building or editing a workflow in Catalyst, ask it to search installable workflows, for example "Search installable workflows before writing new code." Catalyst finds relevant pre-built templates and incorporates them into your automation. To browse the gallery yourself, you can also click **Install workflows** above the message composer on the Catalyst home. ### From the Integrations Page 1. Navigate to **Integrations** in the sidebar 2. Select a connected application 3. Click the **Workflows** tab to launch workflows directly from the application context — no need to leave the app 4. Browse available installable workflows ### From Suggestions Serval's AI analyzes your help desk activity and suggests relevant installable workflows. Review suggestions in: * **Skills** → Suggestions (top right) * **Workflows** → Suggestions To install a suggested workflow, open it in the workflow catalog and stage it for review. *** ## Installing a Workflow Click on an installable workflow to see its description and what it does Check the inputs required and default approval settings. In the Catalyst catalog, select a workflow row to reveal **Who can request** and **Approval**. Use these controls to set who can run the workflow and which approval its runs require. These settings are separate from reviewing and publishing the change set. Choose a destination and select **Install**. Catalyst opens a review session containing the unpublished workflow draft. The session name includes the workflow's name, or the number of selected workflows when you install several at once, so you can find it in recent chats. Adjust settings: * **Name** — Customize for your team * **Approvals** — Change who needs to approve * **Inputs** — Modify required information * **Execution scope** — Set who can run it Review the draft in Catalyst and select **Publish**. Applying the change set publishes the reviewed workflow version and activates its triggers. If the first workflow fails to stage, you stay on the current page and see an error. If a later workflow fails, the drafts already staged remain available in the review. If you start installation from a setup screen, return to that screen after publishing to attach or run the workflow. Preparing a draft doesn't finish setup. *** ## Example Workflows by Integration ### Google Workspace | Workflow | Description | | :- | :- | | Add User to Google Group | Add a user to a Google Group | | Remove User from Google Group | Remove a user from a Google Group | | Create Google Workspace User | Create a new user in Google Workspace | | Create Gmail Delegate | Add a delegate to a Gmail account | | Manage Google Calendar Access | Grant or revoke access to a Google Calendar | | List All Google Groups | List all Google Groups in the workspace | | Create Google User Alias | Create an alias for a Google Workspace user | | Archive Google User | Archive a Google Workspace user account onto an Archived User license | | Transfer Google Drive Ownership | Transfer all of a user's Google Drive files to another user | | Assign Google User License | Assign a Google Workspace product license SKU to a user | ### GitHub | Workflow | Description | | :- | :- | | Add GitHub User to Team | Add a user to a GitHub team | | List GitHub Teams | List all teams in a GitHub organization | | List GitHub Repositories | List all repositories in an organization | | Get GitHub Repository Info | Retrieve details about a repository | | Get GitHub File Contents | Retrieve contents of a file from a repository | ### Okta | Workflow | Description | | :- | :- | | Add User to Okta Group | Add a user to an Okta group | | Remove User from Okta Group | Remove a user from an Okta group | | Create Okta User | Create an Okta user with a temporary password | | Deactivate Okta User | Deactivate an Okta user | | Suspend Okta User | Clear sessions and suspend an Okta user | | Assign User to Okta App | Assign a user to an Okta application | | Unlock User Account | Clear account lockout so the user can sign in | Available workflows vary by integration. Connect an application to see its installable workflows. *** ## Default Approval Settings Installable workflows come with default approval configurations: | Default | Meaning | | :- | :- | | **No approval** | Workflow runs immediately when triggered | | **Installer approval** | The person who installed the workflow must approve runs | You can change the approval configuration after installing to match your security requirements. *** ## Customizing After Installation Installed workflows are fully editable. Common customizations: Require manager or security team approval for sensitive operations Add, remove, or change the information users provide Add steps like Slack notifications or logging Make available to help desk or restrict to team members Installed workflows are independent copies. Customize freely without affecting the original template. *** ## Best Practices Check the workflow logic and ensure it matches your requirements User creation, deactivation, and access changes should require approval Run the workflow manually before making it available to help desk Rename to match your team's terminology and make it easier to find *** ## Supported Integrations Installable workflows are available for 30+ integrations including: Connect an application to see its available installable workflows. # Workflow Types Source: https://docs.serval.com/sections/documentation/workflows/Configure/types Understanding the different types of workflows and when to use each Serval offers multiple workflow types, each designed for specific automation scenarios. Choose the right type based on who triggers the workflow, when it runs, and what it does. ## At a Glance | Type | Triggered by | Best for | | :- | :- | :- | | [**Help desk**](#help-desk-workflows) | Help desk agent | Self-service requests from anyone in the org | | [**Team-only**](#team-only-workflows) | Team members | Internal operations and sensitive tasks | | [**Scheduled**](#scheduled-workflows) | Time schedule | Reports, audits, and recurring maintenance | | [**Webhook-triggered**](#webhook-triggered-workflows) | External HTTP POST | Integrations with external systems | | [**Event-triggered**](#event-triggered-workflows) | Serval events | Automated responses to ticket or access changes | | [**Access provisioning**](#access-provisioning-workflows) | Access requests | Granting application access | | [**Access deprovisioning**](#access-deprovisioning-workflows) | Access requests | Removing application access | | [**Custom approval**](#custom-approval-workflows) | Approval steps | Dynamic approval logic | | [**Knowledge ingestion**](#knowledge-ingestion-workflows) | Knowledge sync | Pulling documents into the knowledge base | *** ## Help Desk Workflows Help desk workflows are available to anyone in your organization through the help desk agent. When a user submits a request via Slack, Teams, or the Serval web app, the agent matches their request to available help desk workflows. **Characteristics:** * Visible to the help desk agent * Can be triggered by any user in the organization * Appear in Help Desk Mode and Silent Mode channels **Use for:** * Password resets * Software installation requests * PTO submissions * Equipment troubleshooting * General IT support requests **Example:** "Reset a user's Okta password and send them instructions via Slack DM" ### How users trigger help desk workflows * **Via chat** — Request the workflow through Slack or Teams DM with the help desk agent * **In app.serval.com** — Click the "Run" button on the workflow * **During tickets** — Agents can run workflows while resolving tickets Help desk workflows should handle common, low-risk requests. For sensitive operations, add an approval step or use a team-only workflow instead. *** ## Team-Only Workflows Team-only workflows are restricted to members of your Serval team. They don't appear to the help desk agent when handling requests from users outside your team. **Characteristics:** * Only visible to team members * Triggered manually or via Team Only Mode channels * Hidden from org-wide help desk requests **Use for:** * User onboarding and offboarding * Security audits and compliance checks * Administrative operations * Sensitive data handling * Internal team processes **Example:** "Offboard a departing employee: disable Okta account, remove from all Google groups, revoke GitHub access, and post summary to #it-ops" ### How users trigger team-only workflows * **Team Only Mode channels** — Message in a connected team-only Slack/Teams channel * **In app.serval.com** — Click the "Run" button on the workflow * **During tickets** — Team agents can run workflows while resolving tickets *** ## Scheduled Workflows Scheduled workflows run automatically on a recurring schedule using cron expressions. They execute without user input at the configured time. **Characteristics:** * Triggered by cron schedule * Run in a specific timezone * Execute without user input (unless configured with defaults) **Use for:** * Daily/weekly reports * Compliance audits * Data synchronization * Cleanup and maintenance tasks * SLA monitoring and alerts **Example:** "Every Monday at 9am, list all open tickets older than 7 days and post a summary to #it-ops" ### Setting up a schedule Select "Scheduled" as the workflow type when creating Set the frequency using preset options (daily, weekly, monthly) or custom cron expressions Select the timezone for schedule evaluation Publish the workflow to activate the schedule ### Common schedules | Schedule | Cron Expression | Description | | :- | :- | :- | | Daily at 9am | `0 9 * * *` | Every day at 9:00 AM | | Weekly Monday 9am | `0 9 * * 1` | Every Monday at 9:00 AM | | Monthly 1st at midnight | `0 0 1 * *` | First day of each month | | Weekdays at 6pm | `0 18 * * 1-5` | Monday-Friday at 6:00 PM | | Every hour | `0 * * * *` | On the hour, every hour | Scheduled workflows run in the timezone you configure. Make sure to set the correct timezone for your team's location. Even scheduled workflows can be run manually for testing or one-off needs. *** ## Webhook-Triggered Workflows Webhook-triggered workflows run when an external system sends an HTTP POST request to the workflow's unique webhook URL. This enables integration with any system that supports webhooks. **Characteristics:** * Triggered by HTTP POST to a unique URL * Receives payload data from the external system * Runs immediately when webhook is received **Use for:** * Responding to events in external systems * Integrating with tools that don't have native Serval integrations * Building event-driven automation pipelines * Processing form submissions or alerts **Example:** "When an expense is submitted in Ramp, send a Slack DM to the employee's manager asking them to review and approve" ### Setting up a webhook trigger Select "Webhook-triggered" as the workflow type when creating After publishing, copy the unique webhook URL from the workflow settings Set up the external system to POST to your webhook URL when the triggering event occurs Copy the webhook secret from the trigger's details dialog and send it using the selected header: `X-Webhook-Secret: YOUR_SECRET` (the default) or `Authorization: Bearer YOUR_SECRET`. The `secret` query parameter is also accepted for backward compatibility. Requests without a valid secret are rejected. Respond to alerts from monitoring tools like Datadog or PagerDuty Process submissions from external forms or portals React to events from systems without native Serval integrations Trigger workflows from deployment or build events The webhook secret is what authenticates the caller, so treat it like any other credential. Anyone holding it can trigger the workflow. ### Rotating a webhook secret You can replace a webhook trigger's secret without changing its URL. Open the trigger's details dialog and choose **Rotate secret**. The previous secret keeps working for 7 days after you rotate, so you can update the sending system without dropping deliveries. While it is still accepted, the dialog shows when it expires and when it was last used, so you can tell whether the sender has picked up the new secret yet. Choose **Revoke now** to end that window immediately, for example when rotating because someone who had access has left. Once the grace window ends, any system still sending the old secret starts getting rejected. Check the "last used" time before revoking, and update the sending system before the window expires. *** ## Event-Triggered Workflows Event-triggered workflows run automatically when specific events occur within Serval. Examples include a ticket being created, a reaction being added to a message, or a ticket being moved to another team. **Characteristics:** * Triggered by internal Serval events * Run automatically without user action * Can filter by event type and conditions **Use for:** * Auto-tagging tickets based on content * Assigning or closing a ticket when a specific reaction is added * Escalating tickets that match certain criteria * Triggering follow-up actions after workflows complete **Example:** "When a new ticket is created, analyze the message and automatically add relevant tags" ### Available event types | Event | Description | | :- | :- | | Any ticket activity | A ticket is created, gets a new message, or has a reaction or label added or removed | | Ticket created | A new help desk ticket is created | | New ticket message | A new message is added to a ticket | | AI agent replied | Serval's AI agent replies on a ticket; the payload includes the reply text | | Ticket escalated | A ticket is escalated to a human | | Ticket assigned | A ticket's assignee changes | | Ticket reaches a terminal status | The ticket moves to a Done or Canceled status | | Message reaction added | A reaction is added to a ticket message | | Message reaction removed | A reaction is removed from a ticket message | | Ticket moved to team | A ticket is moved to this team from another team | | Label added to ticket | A label is added to a ticket | | Label removed from ticket | A label is removed from a ticket | | Ticket feedback submitted | A requester submits or updates their feedback on a ticket | | Approval requested | Something in this team is sent for approval: an access request, a workflow run, or an inline approval | | Approval resolved | An approval reaches its outcome: approved, denied, timed out, or canceled | ### Setting up event triggers Select "Event-triggered" as the workflow type when creating Choose which Serval event should trigger the workflow Filter to specific tickets, labels, or criteria Publish to activate the trigger Be careful with event triggers that create responses or modifications. Test thoroughly to avoid infinite loops or spam. *** ## Access Provisioning Workflows Access provisioning workflows grant users access to applications and resources. They're used by the access management system when processing access requests. **Characteristics:** * Triggered by approved access requests * Receive user and resource information as inputs * Execute the steps needed to grant access **Use for:** * Adding users to application groups * Granting role-based access * Creating accounts in third-party systems * Configuring permissions **Example:** "Add user to the specified GitHub team and grant them the requested repository permissions" Access provisioning workflows are configured in **Access Management**, not the standard Workflows page. See [Access Provisioning](/sections/access-management/configuration/access-provisioning) for details. *** ## Access Deprovisioning Workflows Access deprovisioning workflows remove users from applications and resources. They run when access expires, is revoked, or when a user is offboarded. **Characteristics:** * Triggered by access revocation or expiration * Receive user and resource information as inputs * Execute the steps needed to remove access **Use for:** * Removing users from application groups * Revoking role-based access * Disabling or deleting accounts * Cleaning up permissions **Example:** "Remove user from the Okta group and revoke their AWS IAM role access" Access deprovisioning workflows are configured in **Access Management**, not the standard Workflows page. See [Access Provisioning](/sections/access-management/configuration/access-provisioning) for details. *** ## Custom Approval Workflows Custom approval workflows dynamically determine who should approve a request and whether to auto-approve or auto-deny. They run as part of approval steps in other workflows or access requests. **Characteristics:** * Triggered when an approval decision is needed * Return approval decision: approve, deny, or route to specific approvers * Can access request context to make decisions **Use for:** * Auto-approving low-risk requests * Auto-denying requests that violate policy * Routing approvals based on request attributes * Implementing complex approval logic **Example:** "Auto-approve if the user had this access within the past 30 days. Auto-deny if they were denied in the past 24 hours. Otherwise, route to the resource owner." *** ## Knowledge ingestion workflows Knowledge ingestion workflows feed **searchable documents** into Serval's knowledge base during integration sync. Serval chunks the text, generates embeddings, and surfaces content to the help desk agent with citations back to the source. **Characteristics:** * Run as part of the knowledge sync process for a connected application (not a manual "run workflow" action from chat) * Return structured documents: display name, markdown body, stable external IDs, and URLs used in citations * Support full syncs and incremental (delta) syncs so only changed or removed documents are updated * Distinct from workflows that sync **assets** (devices, accounts, tickets as records) — knowledge ingestion is for articles, wiki pages, handbooks, and other text meant for AI search **Use for:** * Internal wikis or knowledge APIs without a first-party Serval connector * Proprietary or legacy systems where you control the API and map responses into documents * Fine-grained control over which records become knowledge documents and how they are titled or linked **Example:** "On each sync, call our internal handbook API, convert each article to markdown, and emit one knowledge document per article with the public help URL for citations." Knowledge ingestion workflows are authored in code (TypeScript) — ask Catalyst to create a knowledge ingestion workflow and it sets the type for you. They are typically paired with a [Custom App](/sections/integrations/custom-app) or another integration that supports custom workflows. End users manage the resulting source from **Knowledge Base** like any other synced source. See [Knowledge Base](/sections/documentation/knowledge-base/overview) for how this appears in the product. *** ## Choosing the Right Type * **Anyone in the org** → Help desk workflow * **Only team members** → Team-only workflow * **External systems** → Webhook-triggered workflow * **No one (automatic)** → Scheduled or event-triggered workflow * **When a user asks** → Help desk or team-only workflow * **On a schedule** → Scheduled workflow * **When something happens in another system** → Webhook-triggered workflow * **When something happens in Serval** → Event-triggered workflow * **Grants access to an application** → Access provisioning workflow * **Removes access from an application** → Access deprovisioning workflow * **Decides who should approve a request** → Custom approval workflow * **Loads documents into the knowledge base from an API** → Knowledge ingestion workflow * **Everything else** → Help desk, team-only, scheduled, or event-triggered *** ## Best Practices Run manual tests before activating automatic triggers Watch newly configured workflows closely for the first few days Match execution scope to workflow type—event-triggered may need org-wide scope Include trigger conditions in workflow descriptions for clarity # Duplicate Workflows Source: https://docs.serval.com/sections/documentation/workflows/Manage/duplicate Copy workflows within a team or across teams to reuse automations Duplicate workflows to reuse automations across teams without rebuilding from scratch. Each copy is independent—you can customize it for the target team's needs. ## When to Duplicate | Scenario | Example | | :- | :- | | **Same workflow, different teams** | IT and HR both need a user offboarding workflow | | **Template for variations** | Base "send report" workflow customized per team | | **Testing changes safely** | Copy production workflow to test modifications | | **Sharing best practices** | Replicate a successful workflow to other teams | *** ## Duplicate a Workflow Navigate to the workflow you want to duplicate Click the **...** menu in the top right corner of the workflow Click **Duplicate** or **Duplicate to team** Select which team should receive the copy. You can duplicate to: * The same team (creates a copy you can modify) * A different team (where you have manager rights) Click **Duplicate** to create the copy The new workflow opens ready for customization. *** ## What Gets Copied | Copied | Not copied | | :- | :- | | Workflow code and logic | Run history | | Name and description | Version history | | Input configuration | Published state (starts as draft) | | Approval settings | Schedule (must be reconfigured) | | Execution scope setting | Webhook URL (new one generated) | The duplicated workflow starts as a draft. Review the configuration and publish when ready. *** ## After Duplicating ### Check integrations The target team must have access to the same connected applications. If the workflow uses Okta, GitHub, or other integrations, verify: 1. The target team has the integration connected 2. The integration has the required permissions 3. Any referenced resources (groups, repos, etc.) are accessible Workflows will fail if they reference integrations the target team doesn't have. Check the workflow's connected apps before publishing. ### Update team-specific references Some values may need updating for the new team: * Slack channel names or IDs * Group names or IDs * Email addresses or distribution lists * Resource identifiers ### Reconfigure triggers Certain triggers need reconfiguration after duplication: | Trigger type | After duplication | | :- | :- | | Manual | Works immediately | | Scheduled | Must set up schedule again | | Webhook | New webhook URL generated—update external systems | | Event-triggered | May need to reconfigure event filters | ### Adjust execution scope Review who should run this workflow in the new team: * **Anyone in the org** — Available to help desk agent for all users * **Team members only** — Restricted to the target team *** ## Keeping Duplicates in Sync Duplicated workflows stay linked to the original. When the source workflow is updated, you can pull those changes into your copy. ### Pull updates from the original When the source workflow has new versions available: 1. Open the duplicated workflow 2. You'll see a notification that updates are available 3. Review the changes from the source 4. Choose to pull the update or keep your current version This lets teams benefit from improvements to the original while maintaining their own copy. ### When to pull vs. customize | Scenario | Recommendation | | :- | :- | | Source workflow fixed a bug | Pull the update | | Source added a feature you need | Pull the update | | Your team needs different behavior | Keep your version and customize | | Source changed something that breaks your setup | Keep your version | Pull updates regularly to stay current with bug fixes and improvements from the source workflow. *** ## Permissions To duplicate a workflow: * **To the same team** — You need edit access to the team * **To a different team** — You need manager rights on the target team You can only duplicate to teams you have permission to manage. *** ## Best Practices Update the name to reflect the team or purpose: "IT User Offboarding" vs "HR User Offboarding" Check all references, integrations, and settings before making the workflow available Note in the description what was customized from the original Run the workflow manually to verify it works in the new team context # Organizing Workflows Source: https://docs.serval.com/sections/documentation/workflows/Manage/organize Tags, categories, and search for managing workflows at scale As your workflow library grows, organization becomes essential. Use folders, tags, categories, and search to keep workflows discoverable and manageable. Optionally, disable and delete workflows as needed. *** ## Workflow Categories The sidebar automatically organizes workflows into categories: ### Built-in categories | Category | Description | | :- | :- | | **All** | Every workflow in the team | | **Scheduled** | Workflows with scheduled triggers | | **Published** | Active, published workflows | | **Never published** | Draft workflows not yet deployed | | **Has unpublished edits** | Published workflows with pending changes | | **Disabled** | Temporarily turned off workflows | | **Access Provisioning** | Workflows that grant access to users | | **Access Deprovisioning** | Workflows that remove access from users | ### Application categories Workflows are automatically grouped by the applications they interact with. For example: * **AWS** - Workflows using AWS integrations * **GitHub** - Workflows using GitHub integrations * **Google Workspace** - Workflows using Google integrations * **Okta** - Workflows using Okta integrations * **Slack** - Workflows using Slack integrations * *(and more based on your connected apps)* *** ## Folders Folders are manual, nestable containers for grouping related workflows, similar to Serval's automatic categories and custom tags. However, unlike categories and tags, folders give you a hierarchy you arrange yourself. Create folders by team, use case, or product area. For example, keep separate folders for onboarding, offboarding, and device provisioning. You choose a folder when you install or duplicate a workflow, and you can move workflows between folders. You can nest folders, and they can hold both guidance and workflows. Deleting a folder asks whether to move its contents to the parent folder or delete all contents along with it. Right after a delete, choose **Undo** to restore what was removed. Any restored items that were published come back unpublished, so re-publish them if you still need them live. *** ## Tags Tags let you create custom categories for workflows. Unlike automatic categories, tags are fully customizable. ### Creating tags In the workflow sidebar, find the **Tags** section Click the add button next to Tags Select "Create Tag" from the menu * Enter a name for the tag * Choose a color (helps visual identification) The tag is now available to assign to workflows ### Assigning tags to workflows Open the tag management from the sidebar Select an existing tag or create a new one Select which workflows should have this tag The workflows are now tagged and filterable To tag many at once, select items in the list and click **Tags** on the selection bar, then check or uncheck tags to apply or remove them across the whole selection. The same selection bar works on the Help Desk Skills and Forms lists, where tags filter each list the same way they do for workflows. ### Managing tags **Edit a tag:** 1. Hover over the tag in the sidebar 2. Click the menu icon (...) 3. Select "Edit" 4. Update name or color 5. Save changes **Delete a tag:** 1. Hover over the tag in the sidebar 2. Click the menu icon (...) 3. Select "Delete" 4. Confirm deletion Deleting a tag removes it from all workflows but doesn't delete the workflows themselves. ### Tag ideas | Tag | Purpose | | :- | :- | | **Onboarding** | Workflows for new employee setup | | **Offboarding** | Workflows for departing employees | | **Security** | Security-related automation | | **Reports** | Reporting and analytics workflows | | **Compliance** | Compliance and audit workflows | | **Self-service** | User-facing self-service workflows | | **Internal** | Team-internal tooling | | **Critical** | Business-critical workflows | *** ## Search Use search to quickly find workflows by name or description. ### Using search 1. Click in the search field at the top of the workflow list 2. Type your search term 3. Results filter in real-time 4. Click a workflow to open it At **All Workflows**, search finds matching workflows and folder names across the team. Inside a folder, search finds workflows directly in that folder and matching names among its immediate subfolders. Opening a folder keeps your search term active. Clear the search to browse the folder's contents without the text filter. ### Search tips * **Partial matches** - Search finds partial matches in names * **Descriptions** - Search also matches workflow descriptions * **Combine with filters** - Search works within the selected category Use descriptive workflow names to make search more effective. "Create Google Workspace User" is more searchable than "User Setup v2". *** ## Filtering Combine categories, tags, and search for precise filtering: 1. **Select a category** - Start with a built-in category or app 2. **Apply tags** - Further filter by your custom tags 3. **Search** - Narrow down with text search Example: Find all scheduled AWS workflows related to security: 1. Click **Scheduled** category 2. Click **AWS** to filter by app 3. Click **Security** tag 4. Search for "audit" if needed *** ## Best Practices Name workflows clearly: "Weekly Security Audit Report" not "Report v3" Write descriptions explaining what the workflow does and when to use it Establish tag conventions and apply them consistently across workflows Disable or delete workflows that are no longer needed Regularly review your workflow library to keep it organized Use a small set of meaningful tags rather than many specific ones *** ## Organization at Scale As your workflow count grows: ### Naming conventions Establish patterns for workflow names: * `[Team] - [Action] - [Target]` * `[App] - [Operation]` * `[Frequency] [Action] Report` Examples: * "IT - Create User - Google Workspace" * "GitHub - Add to Repository" * "Weekly Security Audit Report" ### Tag taxonomy Create a tag hierarchy: * **By function:** Onboarding, Offboarding, Security, Reports * **By audience:** Self-service, Admin-only, Internal * **By priority:** Critical, Standard, Low-priority ### Team structure Consider how teams map to workflow ownership: * **IT team** - User management, access workflows * **Security team** - Audit and compliance workflows * **Engineering** - Developer tooling workflows * **HR** - People operations workflows *** ## FAQs Yes. Assign as many tags as relevant to a workflow. The workflow appears in each tag's filter. No. Tags are team-specific. Each team manages its own tag taxonomy. Yes. Select multiple items in the list, then use the **Tags** action on the selection bar to add or remove tags across all of them at once. This works on the Workflows, Help Desk Skills, and Forms lists. Click "All" in the sidebar to see every workflow in the team, regardless of category or tag. Disabled workflows appear in the "Disabled" category. They're not hidden from search or "All" view. # Workflow Versioning Source: https://docs.serval.com/sections/documentation/workflows/Manage/versioning Learn how to manage and restore different versions of your workflows # Workflow Versioning Serval automatically tracks all published versions of your workflows, allowing you to view historical changes and restore previous versions when needed. ## Viewing Workflow Versions Hover over the version status in the workflow action bar, then select **Full version history**. This option appears when the workflow has history beyond the version on screen. The sidebar separates **Published versions** from **Draft versions**. Published entries include: * Version numbers * Publication dates and times * Who published each version ## Restoring Previous Versions If you need to revert to an earlier version of your workflow, you can easily restore it: 1. Open **Published versions** in the version history sidebar. 2. Hover over the version you want to restore and select **Restore version**. 3. If the current chat already has staged changes, confirm that you want to replace them. 4. Review the restored draft, then publish it when ready. ## Working with Restored Versions When you restore a previous version: * The selected historical content becomes the working draft in your chat * Existing staged changes in that chat are replaced after confirmation * You can either publish it immediately or make additional modifications before publishing Restoring doesn't change the published workflow until you publish the restored draft. ## Best Practices * **Regular Publishing**: Publish your workflow changes regularly to maintain a comprehensive version history * **Version Notes**: Consider adding descriptive names or comments to significant versions for easier identification * **Testing**: Always test restored versions before publishing to ensure they still work as expected with any system changes # Debugging Workflows Source: https://docs.serval.com/sections/documentation/workflows/Run/debugging Diagnose and fix workflow failures using run history and Catalyst When a workflow fails, Serval gives you two ways to diagnose the issue: manual inspection through run history, and AI-powered debugging with Catalyst. *** ## Diagnose Failures in Run History Every workflow run logs step-by-step execution details. Start here to understand what went wrong. Go to **Workflows**, select the workflow, and click the **Runs** tab. Click on the failed run to open its details. The step-by-step breakdown highlights which step failed. Each step shows its status, duration, input, and output. Check the error message on the failed step. Common errors include: * **Authentication errors**: Expired or revoked API credentials. Reconnect the application in integrations settings. * **Not found errors**: The target resource (user, group, etc.) does not exist. Verify input values. * **Permission errors**: The integration lacks permission for the requested action. Update permissions in the connected application. * **Rate limiting**: Too many API calls in a short period. Wait and retry. * **Timeout errors**: The target application took too long to respond. Retry or check application status. Verify the inputs passed to the failed step were valid. Look for incorrect formats, missing required fields, or references to resources that no longer exist. Either re-run with corrected inputs, or fix the workflow logic and publish a new version. *** ## Debug with Catalyst From any workflow run, click **Investigate in Catalyst** to analyze what happened without digging through logs manually. Catalyst inspects recent runs, identifies which ones failed, and pulls task-level inputs, outputs, and status for each step. It surfaces the exact error and the step that failed, and can suggest fixes. Describe what you want to investigate, for example: * "Why did this workflow fail?" * "What went wrong in the last run?" * "Show me the output of the failed step" You don't need to copy run IDs or open the Runs tab first. Catalyst searches recent runs automatically based on your question. *** ## Tips for Faster Debugging * **Check connected applications first.** Many failures trace back to expired credentials or changed permissions in external systems. * **Compare successful and failed runs.** If the same workflow sometimes succeeds and sometimes fails, compare the inputs between a passing and failing run to isolate the difference. * **Use the builder agent for pattern detection.** Ask the agent to look across multiple recent failures to spot recurring issues. # Individual Workflow Run History Source: https://docs.serval.com/sections/documentation/workflows/Run/run-history Monitor and review workflow execution history Track workflow execution, review results, and debug issues. Every workflow run is logged with detailed step-by-step information. ## Who can view run records Full run history and step details require **View workflow runs** on the team that owns the workflow. This permission applies to the team's runs, not just runs you started. | Role | Full run records by default | | - | - | | Organization Admin without membership in the workflow's team | Yes, through the organization-admin permission set | | Team Agent, Viewer, Drafter, Contributor, Builder, Application Builder, or Manager | Yes, for the workflow's team | | Personal workspace owner | Yes, for that workspace | | Team Read-Only Agent or Restricted | No | | Organization Member without a qualifying team role, or Guest | No | Custom roles, roles inherited through groups, and customized built-in roles can change these defaults. Check the effective **View workflow runs** permission; a role name alone might not describe a user's access. See [Permissions](/sections/documentation/platform/permissions). On an ordinary team, an organization admin with a team membership uses the effective team role permissions; the organization-admin permission set isn't added to them. Organization admins retain administrative authority on the organization management workspace. Some role choices, including Drafter, Application Builder, and Restricted, are available only when enabled for your organization. An Agent can read run details without having permission to browse workflow definitions. Seeing a ticket or a summarized workflow status also doesn't necessarily grant access to full run records. For a workflow shared by another team, the requesting team's result view uses separate shared-workflow permissions and checks the caller's access to the shared workflow. It shows the shared run's result rather than granting access to the owning team's full step history. Run-record access uses Serval permissions. It doesn't recheck each viewer's access to the source systems whose data appears in the run. Consider the audience for run records when choosing which data a workflow processes and retains. *** ## Viewing Workflow Runs Access run history for any workflow: Go to **Workflows** and select the workflow you want to review Click the **Runs** tab to see execution history View all runs sorted by date, with status indicators for each Select any run to see step-by-step execution details *** ## Understanding Run Status Each workflow run has a status indicating its current state: | Status | Meaning | What to do | | :- | :- | :- | | ✅ **Success** | Workflow completed all steps successfully | Review outputs if needed | | ❌ **Failed** | One or more steps encountered an error | Check error details and fix the issue | | ⏳ **Running** | Workflow is currently executing | Wait for completion | | ⏸️ **Pending Approval** | Waiting for approver action | Contact approvers if urgent | | 🚫 **Denied** | Approval was rejected | Review denial reason, adjust and retry if needed | | ⏹️ **Cancelled** | Run was manually cancelled | No action needed | *** ## Run Details Click on any run to see detailed execution information: ### Run summary * **Started at** - When the run began * **Completed at** - When the run finished (or failed) * **Duration** - Total execution time * **Triggered by** - Who or what initiated the run * **Status** - Overall result ### Step-by-step breakdown Each workflow step is logged with: * **Step name** - What action was performed * **Status** - Success, failure, or skipped * **Duration** - How long the step took * **Input** - What data was passed to the step * **Output** - What the step returned * **Error** - Error message if the step failed Use the step-by-step breakdown to identify exactly where issues occurred. Failed steps show the specific error that caused the failure. *** ## Debugging Failed Runs When a workflow fails, follow these steps to diagnose and fix the issue: Open the run details and find the step marked as failed Check the error details for: * API errors from connected applications * Invalid input values * Permission or authentication issues * Network or timeout errors Verify the inputs provided were valid: * Correct format (email, date, etc.) * Valid values (existing users, resources, etc.) * Required fields were populated Check if the target application is: * Available and responding * Properly connected to Serval * Permissions are still valid Either: * Re-run with corrected inputs * Fix the workflow logic and publish a new version * Contact support if the issue persists ### Common failure causes **Symptom:** "Unauthorized" or "Authentication failed" errors **Cause:** API credentials expired or were revoked **Fix:** Reconnect the application in Serval's integrations settings **Symptom:** "Resource not found" or "User does not exist" errors **Cause:** The target resource (user, group, repo, etc.) doesn't exist **Fix:** Verify the input values are correct and the resource exists **Symptom:** "Forbidden" or "Insufficient permissions" errors **Cause:** Serval's integration lacks permission for the requested action **Fix:** Update the integration's permissions in the connected application **Symptom:** "Rate limit exceeded" or "Too many requests" errors **Cause:** Too many API calls to the application in a short period **Fix:** Wait and retry, or spread out workflow executions **Symptom:** "Timeout" or "Request took too long" errors **Cause:** The target application took too long to respond **Fix:** Retry the run, or check if the application is experiencing issues *** ## Filtering and Searching Runs For workflows with many runs, use filters in the run-history header to find specific executions: * **Status** - Show only runs in the statuses you pick. Use the **is** / **is not** operator to include or exclude specific statuses (for example, Completed, Failed, or Running). * **Date started** - Filter to runs that started within a date window. * **Date completed** - Filter to runs that finished within a date window. Filters combine, and run numbers stay consistent while a filter is applied, so a run keeps the same number whether or not the list is filtered. *** ## Scheduled Workflow Runs For scheduled workflows, the Runs tab shows: * All scheduled executions that have occurred * The next scheduled run time * Whether scheduled runs are succeeding consistently If a scheduled workflow consistently fails, it will keep trying at each scheduled time. Review and fix failures promptly to avoid repeated errors. *** ## Exporting Run Data Export workflow run history for reporting or compliance: 1. Navigate to the workflow's Runs tab 2. Apply any filters needed 3. Click **Export** or **Download** 4. Choose your format (CSV, JSON) Exports include: * Run timestamps * Status * Duration * Who triggered the run * Input values * Success/failure details *** ## Best Practices Check run history weekly to catch issues before they become problems Create a workflow that notifies you when other workflows fail Ensure scheduled workflows are running successfully on their expected cadence Disable or delete workflows that consistently fail or are no longer needed # Triggers Source: https://docs.serval.com/sections/documentation/workflows/Run/triggers Learn how workflows are triggered Workflow triggers are defined by the workflow type you choose when creating a workflow. Each type has its own trigger mechanism—from manual execution to scheduled runs to webhook calls. Learn about all workflow types and how each is triggered ## Quick Reference | Workflow Type | How it's triggered | | :- | :- | | Help desk | Users request via chat or web app and the help desk agent discerns which automation to run | | Team-only | Team request run manually or via chat and the help desk agent discerns which automation to run | | Scheduled | Cron schedule (time-based) | | Webhook-triggered | External HTTP POST request | | Event-triggered | Serval events (tickets, access, etc.) | | Access provisioning | Approved access requests | | Access deprovisioning | Access revocation or expiration | | Custom approval | Approval steps in other workflows | # Build Your First Workflow Source: https://docs.serval.com/sections/documentation/workflows/create-your-first-workflow Build and publish a workflow in minutes using natural language This guide walks you through creating, testing, and publishing your first workflow in Catalyst. By the end, you'll have a working automation ready to run. ## Before You Start * Open your team, then click **Catalyst** in the sidebar * You need **Builder** permissions or higher to publish *** ## Build Your First Workflow Click **Catalyst** in the sidebar. You land on the chat view with a new-session composer. Tell Catalyst what you want to automate in plain language. Be specific about: * **What** the workflow should do * **When** it should run (if not manual) * **Which apps** it should connect to Catalyst asks follow-up questions if it needs clarification. **Example prompts:** * "Reset a user's password in Okta and send them a Slack DM with instructions" * "Every Monday at 9am, list open tickets older than 7 days and post to #it-ops" * "When a user is added to the Engineering group in Okta, add them to the engineering GitHub team" Catalyst drafts the workflow and opens it in the resource panel, where you can review a summary, the generated code, and each step. Request changes in chat: "Add an approval step before resetting the password" or "Also send a confirmation email." Catalyst chat and resource panel showing a workflow draft ready to publish After Catalyst creates the workflow, it asks if you want to test it. Run a test to check each step's status and its input and output before you publish. If your team allows direct publishing, click **Publish** on the workflow tab or above the chat composer. If your team requires review before publishing, click **Propose for review**. Once published: * Help desk workflows become available to the help desk agent immediately * Scheduled workflows start running on their configured schedule * Team-only workflows appear in your team's workflow list For the full Catalyst guide, see [Getting started with Catalyst](/sections/documentation/catalyst/getting-started). *** ## Configure Your Workflow After creating a workflow, you can configure additional settings: Configure when workflows run: manually, on schedule, or via webhook Require approval before sensitive workflows execute Collect information from users before the workflow runs Control who can run the workflow: org-wide or team-only *** ## Tips for Better Workflows "Reset Okta password" works better than "help with access" Mention which integrations to use: "in Slack," "via GitHub," "using Okta" Start simple, test, then add complexity through follow-up prompts # Workflows Overview Source: https://docs.serval.com/sections/documentation/workflows/overview Build, run, manage, and audit automations across your organization Serval workflows are AI-powered automation tools that help streamline tasks and processes across your organization. Vibe code workflows using natural language, connect them to your applications, and automate everything from user provisioning to scheduled reports. You build and edit workflows in [Catalyst](/sections/documentation/catalyst/overview), Serval's automation agent. This section covers how workflows run, trigger, integrate, and how you manage them once built. ## Why Workflows * **Build and edit with natural language** - Describe what you want in plain English; Serval generates the code * **Edit the code directly** - Optionally, edit code directly to adjust workflows * **Visualize every step** - See exactly what your workflow does in an easy-to-follow diagram * **Control access and approvals** - Set permissions for who can run workflows and require approvals before execution * **Run deterministically** - Workflows execute exactly as written, every time * **Connect to anything** - Interact with any API you've connected to Serval, or trigger workflows via webhook, schedule, or help desk agent * **Long-running support** - Workflows can run for hours or days without timing out, with reliable progress tracking and cancellation * **File inputs and outputs** - Accept files as workflow inputs and return files as outputs to process documents, generate reports, or move files between systems * **Find workflows with semantic search** - Search workflows by intent, not just keywords. Results are ranked by semantic relevance * **Organize with tags** - Create custom tags to categorize and filter workflows in the sidebar * **React to events** - Build event-triggered workflows that respond to Serval events like ticket creation, updates, and new messages ## What You Can Do with Workflows Create workflows using natural language or edit the generated code directly. Install workflows for an easy start Execute workflows manually, on schedules, or triggered automatically from tickets Duplicate workflows across teams and maintain versions over time View complete logs of all workflow runs and configuration changes ## Next Steps Start by [creating your first workflow](/sections/documentation/workflows/create-your-first-workflow) or [installing a pre-built workflow](/sections/documentation/workflows/Configure/installable). # Absolute Source: https://docs.serval.com/sections/integrations/absolute Connect Serval to Absolute Secure Endpoint so workflows can query and manage devices, run remote actions, and call the Absolute v3 API with asymmetric token authentication. ## About Absolute Absolute Secure Endpoint (formerly Absolute Visibility / Persistence) is endpoint resilience and security software for laptops, desktops, and Chromebooks. The Serval Absolute integration connects to your Secure Endpoint Console using an asymmetric API token. Serval signs each API call with your EC P-256 private key and sends it to the regional Absolute API host you select. There is no browser sign-in and no long-lived bearer token stored in workflows. **Authentication:** Asymmetric API token (Token ID + EC P-256 private key PEM). Serval constructs a JSON Web Signature for every request and posts it to Absolute's `/jws/validate` endpoint on your configured API domain. **Data sync:** On demand only. Workflows call the Absolute API when they run; there is no background sync or asset ingestion. ## What the Absolute integration enables | Capability | Description | | - | - | | Absolute API request | Typed access to the Absolute v3 REST API from custom workflows — devices, device groups, users, applications, freeze/unfreeze, messaging, geofences, and other Secure Endpoint operations supported by your token's permissions. | | Regional API routing | Choose the API domain that matches your Secure Endpoint Console login URL (Global, US, EU, India, or US Gov). Serval only sends signed requests to the five supported Absolute API hosts. | Anything defined in the [Absolute API documentation](https://api.absolute.com/) for your region can be accessed through Serval, subject to the permissions on your API token. ## Get your credentials Serval needs four values from Absolute Secure Endpoint Console: an instance name (for your own labeling), the matching API domain, a Token ID, and the PEM-encoded EC P-256 private key that pairs with the public key uploaded when the token was created. Open the console URL your organization uses (for example `https://secure.absolute.com` or a regional variant) and sign in with an account that can manage API tokens. In Secure Endpoint Console, create a new API token using Absolute's asymmetric (public/private key) flow. Upload an EC P-256 public key in PEM format when prompted. When the token is created, copy its **Token ID**. Serval uses this as the JWS key identifier (`kid`) on every signed request. Use the EC P-256 private key PEM that corresponds to the public key you uploaded. Serval stores it encrypted and uses it only server-side to sign requests — it is never exposed to workflow code. Match the API domain to the console region you use. The connect form offers Global (`api.absolute.com`), US (`api.us.absolute.com`), EU (`api.eu2.absolute.com`), India (`api.in1.absolute.com`), and US Gov (`api.fr1.absolutegov.com`). If you rotate or replace the token in Absolute, update both the Token ID and private key in Serval. A mismatched key pair fails every API call with an authentication error. ## Connect in Serval In Serval, add the Absolute integration. Enter a label for this connection (for example `Production` or `Corporate`). This helps your team distinguish multiple Absolute installs. Select the regional API host that matches your Secure Endpoint Console login URL. Paste the Token ID from the asymmetric API token you created in Absolute. Paste the full PEM-encoded EC P-256 private key, including the `-----BEGIN` / `-----END` lines. Submit the form. Serval stores the private key encrypted and configures signing for your selected API domain. When editing an existing connection, the stored private key is shown obfuscated. Re-paste the full PEM to rotate credentials; leave other fields unchanged to keep their stored values. ## Gotchas and troubleshooting Serval only attaches credentials to requests bound for the five supported Absolute API hosts. Choosing the wrong region causes authentication failures even when the Token ID and private key are correct. Absolute asymmetric tokens require an Elliptic Curve key on the NIST P-256 curve. PKCS#8 or SEC1 PEM encodings are both accepted. Other key types are rejected at signing time. The API token's permission set in Absolute determines which endpoints succeed. A 403 from a workflow usually means the token lacks the privilege for that resource — adjust the token in Secure Endpoint Console, not Serval. If your token has an IP allowlist in Absolute, ensure Serval's outbound addresses are permitted or the allowlist is disabled for this token. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Absolute integration. # Absorb LMS Source: https://docs.serval.com/sections/integrations/absorb-lms Connect Absorb LMS to Serval to read users, courses, enrollments, and other LMS data through the Integration API ## About Absorb LMS Absorb LMS is a cloud learning management system for employee training, compliance, and certification programs. Connecting Absorb LMS to Serval lets workflows query LMS data — users, courses, enrollments, departments, and related records — through the [Absorb Integration API](https://docs.myabsorb.com/integration-api/v2/docs) without exposing API credentials to workflow authors. This integration is **read-only**: it exposes 36 GET endpoints from the Integration API v2 spec. Write operations (creating users, enrolling learners, updating courses) are not available through Serval. The Absorb LMS integration is in **beta**. Behavior and endpoint coverage may change as we expand the integration. ## What the Absorb LMS integration enables | Capability | Description | | - | - | | User data | List and retrieve LMS users, authenticated admin profile, user management settings, certificates, and competencies | | Courses | Read online courses, instructor-led courses, curricula, course sessions, and session details | | Enrollments | List and retrieve course enrollments for users and courses, including the authenticated admin's own enrollments | | Organization | Read departments, groups, categories, roles, and custom field definitions | | Learning structure | Read prerequisites, learning paths, and enrollment keys | | Workflow automation | Call any supported GET endpoint from Serval workflows via the **Absorb LMS API request** action | Anything defined in the [Absorb Integration API v2 documentation](https://docs.myabsorb.com/integration-api/v2/docs) that is exposed as a GET in our spec can be accessed through Serval. *** ## Prerequisites Before connecting Absorb LMS to Serval, you will need: 1. **Admin access** to your Absorb LMS portal (required to view Portal Settings and retrieve the private API key). 2. The **Integration API add-on** enabled on your Absorb portal. Absorb provisions a **private API key** tied to your portal when Integration API access is active. If you do not see a Rest API Private Key in Portal Settings, contact your Absorb account team. 3. **Admin username and password** for an Absorb administrator whose role grants access to the data you plan to read. The admin's permissions in the LMS determine which API endpoints return data. *** ## Retrieve your Absorb LMS credentials Sign in to your Absorb LMS portal. If the Integration API add-on is enabled, you can retrieve a private API key from Portal Settings. If the key field is missing, work with your Absorb account team to enable Integration API access before continuing. In the Absorb admin interface: 1. Click the **menu icon** and select **Admin**. 2. Click the **account icon** and select **Portal Settings**. 3. Scroll to **Rest API Private Key** and copy the value. Treat the private API key like a password. Do not paste it into source control or share it across teams. If it is compromised, contact your Absorb administrator to rotate it. Absorb serves the Integration API from regional gateway hosts separate from your learner-facing portal URL. Use the host that matches your organization's region: | Region | API host | | - | - | | United States | `rest.myabsorb.com` | | Canada | `rest.myabsorb.ca` | | Europe | `rest.myabsorb.eu` | | Australia | `rest.myabsorb.com.au` | | United Kingdom | `rest.myabsorb.co.uk` | | Sandbox | `rest.sandbox.myabsorb.com` | Paste only the hostname — no `https://` prefix and no path. Select an Absorb admin username and password to use for API authentication. A **System Admin** can access the broadest set of endpoints. The admin's LMS role determines what data the Integration API returns. *** ## Connect Absorb LMS to Serval Navigate to **Integrations** → **All integrations** → **Absorb LMS** → **Connect**. Paste the values you captured above: | Field | Value | | - | - | | **API Host** | Your regional Integration API gateway (e.g. `rest.myabsorb.com`, `rest.myabsorb.eu`, `rest.myabsorb.ca`, `rest.myabsorb.com.au`, or `rest.sandbox.myabsorb.com`). | | **Private API Key** | The Rest API Private Key from Absorb Portal Settings. Sent as the `x-api-key` header on every request. | | **Admin Username** | Absorb admin username used to obtain API tokens via `/authenticate`. | | **Admin Password** | Password for the admin account. Stored encrypted; used only by the Serval proxy to mint short-lived bearer tokens. | Click **Save**. Open the connected Absorb LMS integration and run health checks: * **\<001> Test Connection** — fetches the authenticated admin profile via `/my-details`. * **\<002> List Users**, **\<003> List Online Courses**, **\<004> List My Enrollments**, **\<005> List Departments**, **\<006> List Categories** — confirm read access to common LMS resources. A successful **Test Connection** result confirms Serval minted a bearer token with your credentials and that Absorb accepted the request. *** ## How authentication works Every time a Serval workflow calls the Absorb Integration API, the Serval proxy: 1. Decrypts your stored private API key, admin username, and admin password. None of these values leave the proxy — workflow code only sees an opaque integration ID. 2. Calls `POST https://{apiHost}/authenticate` with a JSON body containing your admin username and password, plus headers `x-api-key`, `x-api-version: 2`, and `Content-Type: application/json`. 3. Receives a short-lived bearer token from Absorb and caches it until five minutes before expiry, then refreshes automatically. 4. Attaches these headers to the outbound API request: * `x-api-key: ` * `Authorization: Bearer ` * `x-api-version: 2` 5. Forwards the request to your configured API host and streams the response back to the workflow. The proxy only allows requests to Absorb Integration API gateway hosts matching your configured region. *** ## Using Absorb LMS in workflows Once connected, call Absorb from workflows with the **Absorb LMS API request** action. Pass the `path`, `method`, and optional `query` — Serval resolves the API host from the connection and injects authentication automatically. List endpoints support offset-based pagination with `_offset` and `_limit` query parameters, plus optional `_sort`, `_filter`, and `modifiedSince` on many resources: ``` GET /users?_offset=0&_limit=100 GET /online-courses?_offset=0&_limit=50&modifiedSince=2024-01-01T00:00:00Z ``` *** ## Rotating credentials 1. In Absorb, rotate the Rest API Private Key or update the admin password as needed through Portal Settings or your admin user management. 2. In Serval, open the Absorb LMS integration's configuration form. 3. Paste the new values. Leaving a password field blank preserves the previously stored value, so you must paste a new password explicitly for it to take effect. 4. Save and re-run **Test Connection**. *** ## Troubleshooting **Health check fails with 401 Unauthorized.** - Verify the private API key exactly matches the value in Absorb Portal Settings — no leading or trailing whitespace. - Confirm the admin username and password are correct and the account is active. - Confirm Integration API access is enabled on your portal. **Health check fails with a connection or DNS error.** - The **API Host** is wrong. Use the regional Integration API gateway (e.g. `rest.myabsorb.com`), not your learner-facing portal URL (e.g. `yourcompany.myabsorb.com`). - Paste only the hostname, with no `https://` prefix and no path. **Health check succeeds but list endpoints return empty or 403.** - The admin account may lack permission for that resource. Try a System Admin account or adjust the admin's LMS role in Absorb. *** ## External resources * [Absorb Integration API v2 documentation](https://docs.myabsorb.com/integration-api/v2/docs) — endpoint reference and authentication details. * [Getting Started with the Absorb Integration API](https://support.absorblms.com/hc/en-us/articles/222482188-Getting-Started-with-the-Absorb-Integration-API) — Absorb Help Center guide for token generation and portal setup. Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Absorb LMS integration. # Adobe Source: https://docs.serval.com/sections/integrations/adobe Connect Serval to the Adobe User Management API to assign and remove Adobe product profiles (licenses) through provisioning and deprovisioning workflows. ## About Adobe The Adobe integration connects Serval to the [Adobe User Management API](https://adobe-apiplatform.github.io/umapi-documentation/en/), the same API that powers user and license administration behind the [Adobe Admin Console](https://adminconsole.adobe.com). Adobe licenses its creative, document, and marketing software (Creative Cloud, Document Cloud, and Experience Cloud) to users through that console. Once connected, Serval can assign and remove Adobe product profiles (licenses) for your users through an installable "Access Management" workflow bundle, and custom workflows can call any part of the User Management API. Workflow requests go to a single Adobe API host for this integration, usermanagement.adobe.io. **Authentication:** OAuth Server-to-Server (client credentials) via Adobe IMS - you paste an Organization ID, Client ID, and Client Secret from the Adobe Developer Console, and Serval handles token exchange and all API authentication headers automatically. No user login or browser-based OAuth flow is involved - the credential acts on behalf of your organization. **Data sync:** On demand only. Serval does not import or sync Adobe users, licenses, or other resources in the background - Adobe is contacted only when a workflow runs (or when the connection health check runs). The integration surface is focused on the Adobe User Management API (`usermanagement.adobe.io`). Other Adobe APIs (Creative Cloud Libraries, Photoshop API, and similar) are not exposed. ## What the Adobe integration enables | Capability | Description | | - | - | | Provision User to Adobe | Installable workflow (part of the "Access Management" bundle) designed as an app entitlement's custom provisioning workflow. Creates the user in Adobe if needed (as a Federated ID) and assigns the Adobe product profile whose name matches the requested Serval role - no mapping configuration required. | | Deprovision User from Adobe | Installable workflow in the same bundle, designed as an app entitlement's custom deprovisioning workflow. Removes the Adobe product profile whose name matches the revoked entitlement. Works for both access-request-backed removals and access-review remediations. Removes the license only, not Adobe organization membership. | | Adobe API request | A general-purpose action that lets any custom workflow call the Adobe User Management API directly. Serval injects authentication (including Adobe's required API key header) automatically, so workflows never handle credentials. | Anything defined in the [Adobe User Management API](https://adobe-apiplatform.github.io/umapi-documentation/en/) can be accessed through Serval, including: * Listing and looking up users in your Adobe organization * Creating users and assigning or removing product profiles (licenses) * Managing user groups and group membership * Removing users from the organization Common use cases include self-service Creative Cloud license requests with approval, automatic license reclamation during offboarding, license-tier changes (for example, Single App to All Apps), and periodic audits of who holds which product profile. ## Get your credentials Serval connects using an **OAuth Server-to-Server credential** from an Adobe Developer Console project that includes the **User Management API**. Adobe's official setup guide is the [UMAPI authentication documentation](https://adobe-apiplatform.github.io/umapi-documentation/en/UM_Authentication.html); the credential type itself is covered in the [Adobe OAuth Server-to-Server implementation guide](https://developer.adobe.com/developer-console/docs/guides/authentication/ServerToServerAuthentication/implementation). Only members of your Adobe organization with the **System Admin** role can create the User Management API integration in the Adobe Developer Console. Have a system admin perform these steps. Go to the [Adobe Developer Console](https://developer.adobe.com/console) and sign in as an Adobe System Administrator. Make sure the correct organization is selected in the top-right org picker - the credential is only valid for the org that is selected when you create the project. Create a new project (or open an existing one) and choose **Add API**. Select the **User Management API** (listed under Adobe Services), choose the **OAuth Server-to-Server** credential type, and click **Save configured API**. Adding the User Management API automatically attaches the scopes the credential needs (openid, AdobeID, user\_management\_sdk) - you do not configure scopes by hand, and Serval requests exactly these during the token exchange. Open the project's OAuth Server-to-Server credential overview page. Copy the **Client ID** (this is also your API key) and use **Retrieve client secret** to get the **Client Secret**. Your Organization ID is a 24-character alphanumeric string followed by the **@AdobeOrg** suffix (33 characters in total, for example 1234567890ABCDEF12345678\@AdobeOrg). It is shown alongside the project credentials in the Developer Console (and under Project overview), and also appears in your Adobe Admin Console URL. See [Find your Adobe Organization ID](https://experienceleague.adobe.com/en/docs/core-services/interface/administration/organizations) if you have trouble locating it. The credential must include the **User Management API**. A credential created without it cannot grant the permissions Serval requests, and the connection will fail when Adobe rejects the token exchange or the first API call. The Client ID is only authorized for the APIs attached to its own project. ## Connect in Serval In Serval, go to **Integrations -> All integrations -> Adobe** and click **Connect**. In **Organization ID**, paste your Adobe organization ID. Helper text: "Your Adobe organization ID (ends with @AdobeOrg)." In **Client ID (API Key)**, paste the Client ID from your credential. Helper text: "The Client ID of your Adobe OAuth Server-to-Server credential." In **Client Secret** (a password field), paste the Client Secret. Helper text: "The Client Secret of your Adobe OAuth Server-to-Server credential." Click **Submit**. Serval exchanges the credentials for an access token with Adobe IMS and runs a read-only health check that lists the first page of users in your organization. This exercises the full auth path - the token exchange, the API key header, and org access - so a passing check means the integration is ready to use. The connection appears as "Adobe (\[organization ID])". All three fields are needed for a working connection, but the form does not mark them with asterisks or block a blank submit - a missing or mistyped value surfaces when the health check or a workflow first calls Adobe. If saving fails, the form shows "Failed to install integration" or "Failed to update integration" (with details appended when available). Adobe access tokens are short-lived; Serval refreshes them automatically using the stored credential. You never need to rotate tokens by hand - only the client secret, if your security policy requires it. When editing an existing connection, fields you leave blank (or leave showing their obfuscated placeholder) keep their stored values. To rotate just the Client Secret, click the pencil icon next to the masked value (or **Replace** on the reconnect form), paste the new secret into the "Enter new value" box, and save - you do not need to re-enter the Organization ID or Client ID. If you rotate the secret in the Adobe Developer Console, update it in Serval as well, because the old secret stops working as soon as rotation completes. ## Verifying the connection When you save the connection, Serval runs a read-only health check that lists the first page of users in your organization. A passing check proves the whole authentication path at once: the token exchange with Adobe IMS, the API key header, and access to your organization. If it fails, re-verify the three values against the credential page in the Adobe Developer Console and confirm the credential includes the User Management API. You can also confirm the connection works end to end by running a workflow that reads from Adobe - for example, a small custom workflow that uses the Adobe API request action to list the users in your organization. Successful authentication does not guarantee provisioning will succeed. The most common failure after Adobe accepts your credentials is a product profile name mismatch - the Serval role or entitlement name must exactly match a product profile name in your Adobe Admin Console. ## Installable workflow bundle The integration ships with an **Access Management** bundle you can install from **Integrations -> Adobe -> Workflows**: * **Provision User to Adobe** - assigns the requested Adobe product profile (license) to a user. If the user does not exist in your Adobe organization yet, the workflow first creates a Federated ID for them, then adds the product profile. Install it, then select it as an app entitlement's **custom provisioning workflow**. * **Deprovision User from Adobe** - removes the revoked product profile from a user. Select it as the entitlement's **custom deprovisioning workflow**. The user stays in the organization; only the license is reclaimed. Works for both access-request-backed removals and access-review remediations. These workflows are deliberately plug-and-play with no role-mapping table to maintain. The Adobe product profile comes straight from the Serval role's name (provisioning) and the revoked entitlement's name (deprovisioning), sent to Adobe verbatim. Name your Serval roles and entitlements to exactly match the product profile strings in your Adobe Admin Console (for example, "Default All Apps configuration"). Two scoping assumptions to check before installing: * **Identity type**: user creation assumes your organization uses **Federated IDs** (SSO-backed). If you use Enterprise IDs or Business IDs, or rely on SSO just-in-time provisioning, adjust the user-creation step after installing. * **SSO access is separate**: these workflows manage only the Adobe license. If sign-in to Adobe is gated by an IdP or directory group, grant or revoke that group in your IdP (or as its own Serval step) - assigning a product profile does not by itself let the user log in. ## Using Adobe in workflows Once connected, use the **Adobe API request** action to call any User Management API endpoint. The action is schema-less - pass the path, method, and body directly, and resolve request and response shapes from the [UMAPI documentation](https://adobe-apiplatform.github.io/umapi-documentation/en/). Serval injects authentication automatically on every call, so workflows never handle credentials: * The **Bearer token** from the OAuth Server-to-Server exchange. * The **X-Api-Key header** (your Client ID), which Adobe requires on every request. Serval always sets this and a workflow cannot override it. Your organization ID is available from the integration context, so workflows never hardcode it: ```typescript theme={null} import { workflow } from "serval/core"; import * as adobe from "serval/integrations/adobe"; export const main = workflow({ fn: async (_args: {}, ctx: adobe.context.AdobeIntegration) => { const { orgId } = ctx.integrations.adobe; // List the first page of users in the organization. return await adobe.apiRequest( { path: `/v2/usermanagement/users/${encodeURIComponent(orgId)}/0`, method: "GET", }, ctx, ); }, }); ``` ### Common endpoints | Path | Method | Notes | | - | - | - | | `/v2/usermanagement/users/{orgId}/{page}` | GET | List users, paginated by page number. The response's `lastPage` flag tells you when to stop. | | `/v2/usermanagement/organizations/{orgId}/users/{userString}` | GET | Look up a single user by email. | | `/v2/usermanagement/groups/{orgId}/{page}` | GET | List user groups and product profiles. | | `/v2/usermanagement/action/{orgId}` | POST | The batch action API - create users, add or remove product profiles and user groups, and remove users from the org. Each entry's `do` array runs steps in order. | The action API returns a summary (`result`, `completed`, `notCompleted`, `errors`) rather than failing the HTTP request, so always check `notCompleted` and `errors` in your workflow. The pre-built provisioning workflows above already do this and fail loudly on partial completion. Adobe throttles the User Management API per organization. If you build bulk workflows (for example, a license audit across thousands of users), expect occasional `429` responses and retry with backoff per the `Retry-After` header. See Adobe's [UMAPI documentation](https://adobe-apiplatform.github.io/umapi-documentation/en/api/getUsersWithPage.html) for current limits and the [action commands reference](https://adobe-apiplatform.github.io/umapi-documentation/en/api/ActionsCmds.html) for batch request shapes. ## Gotchas and troubleshooting The installed workflows are deliberately plug-and-play with no mapping layer: the requested role's name (provisioning) and the revoked entitlement's name (deprovisioning) are sent to Adobe verbatim as the product profile to assign or remove. Name your Serval roles and entitlements to match the exact product profile strings in your Adobe Admin Console (for example, "Default All Apps configuration"), including case and spacing, or the workflow fails with an Adobe error. When using the Adobe API request action directly, check the `errors` array in the action API response - Adobe returns a per-entry `errorCode` and `message` identifying the failing step. The Provision User to Adobe workflow creates users as Federated IDs (skipping creation if the user already exists), which assumes your organization uses Federated IDs (SSO). Organizations using Enterprise or Business IDs, or SSO just-in-time provisioning, should adjust or remove that step after installing. The country defaults to "US" and first/last names are derived from the email address - enrich the workflow from your HR system or identity provider if accurate names matter. Both workflows manage only the Adobe license (product profile). Sign-in access through your identity provider or a directory group is a separate access grant managed in your IdP or as its own Serval step - assigning a product profile does not by itself let the user log in. Deprovisioning removes one product profile; it does not remove the user from your Adobe organization. Serval requests Adobe's user management permissions (the openid, AdobeID, and user\_management\_sdk scopes) when exchanging tokens. A credential created without the User Management API cannot grant them, so the token exchange or the first API call fails even though the Client ID and Secret look valid. Add the User Management API to the project in the Adobe Developer Console, and confirm it is attached to the same project as the credential. Confirm the **Organization ID** ends with @AdobeOrg and matches the org that was selected in the Developer Console when you created the project. Confirm the credential is **OAuth Server-to-Server** - not JWT (Adobe's deprecated Service Account credential type) and not an OAuth Web App credential. Confirm the **User Management API** is added to the same project as the credential. The client secret may have been rotated in the Adobe Developer Console. Update the secret in Serval via **Integrations -> Adobe -> Configure**; the old secret stops working as soon as rotation completes. Per Adobe's documentation, only members of the organization with the System Admin role can create the User Management API integration in the Adobe Developer Console. If you cannot add the API or see the credential, ask a system admin to create the project for you. The edit form shows the saved Client Secret obfuscated (bullet characters plus its last 4 characters). Submitting with untouched or blank fields keeps the stored Organization ID, Client ID, and Client Secret, so you can safely update a single field without re-entering the others. Serval does not ship a generated catalog of Adobe endpoints. Custom workflows using the Adobe API request action should consult Adobe's online references for request and response shapes - the [UMAPI documentation](https://adobe-apiplatform.github.io/umapi-documentation/en/) and the [action commands reference](https://adobe-apiplatform.github.io/umapi-documentation/en/api/ActionsCmds.html). Authentication, including Adobe's required API key header, is always added by Serval automatically and cannot be overridden by a workflow. ## External Resources * [Adobe Developer Console](https://developer.adobe.com/console) * [User Management API documentation](https://adobe-apiplatform.github.io/umapi-documentation/en/) * [OAuth Server-to-Server credentials guide](https://developer.adobe.com/developer-console/docs/guides/authentication/ServerToServerAuthentication/) * [Adobe Admin Console](https://adminconsole.adobe.com) *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Adobe integration. # ADP Source: https://docs.serval.com/sections/integrations/adp Connect ADP to Serval to automate HR and payroll workflows ## About ADP ADP is one of the largest providers of payroll, HR, tax, and benefits administration software, serving organizations through platforms such as ADP Workforce Now, Vantage HCM, GlobalView, and RUN. Connecting ADP to Serval lets your team query worker data and automate employee-lifecycle and payroll-adjacent workflows against ADP's REST APIs. Your ADP administrator controls which ADP products and data your connection can access. ## What the ADP integration enables | Capability | Description | | - | - | | Worker data access | Read worker and HR data your ADP API client is allowed to access | | Workflow automation | Use approved ADP data in Serval workflows | ADP permissions are managed in ADP, not in Serval. If a workflow cannot read the data you expect, ask your ADP administrator or representative to confirm the right ADP products and data permissions are enabled. ## How ADP authentication works ADP uses a secure app-to-app authentication flow. To connect ADP to Serval, you provide the credentials and certificate material for an ADP API client that your organization controls. Serval stores secret values encrypted and uses them to authenticate with ADP when workflows run. You do not need to handle ADP access tokens yourself. Connecting ADP to Serval requires these values: | Credential | What it is | | - | - | | **Client ID** | The identifier of your ADP API client | | **Client Secret** | The secret paired with the Client ID | | **Client Certificate** | The certificate ADP issued or registered for this API client | | **Private Key** | The private key matching that certificate | | **Region** | The ADP region for your organization | If you're not sure which region to use, ask your ADP representative. *** ## ADP configuration ### Prerequisites * An ADP product with API access (for example ADP Workforce Now, Vantage HCM, or GlobalView) * Either ADP's self-service API administration product or an ADP representative who can provision a custom API integration for you * Administrator access to API Central, if you're using the self-service path ### Step 1: Get a Client ID and Client Secret **If your organization uses ADP API Central:** sign in, create or open the API project for this integration, and copy its generated **Client ID** and **Client Secret**. **If not:** your ADP representative can provision an API client for a custom integration and deliver the Client ID and Client Secret to you. ### Step 2: Get the certificate and private key ADP issues or registers a certificate for each API client. There are two common ways to obtain one: * **Generate it in ADP API Central.** API Central can create the certificate and key pair for you. Save the certificate and private key immediately. If you lose the private key, you must generate a new certificate. * **Bring your own key.** Generate a key pair yourself, submit the request to ADP through your usual ADP process, and ADP returns the signed certificate. You keep the private key. Track the certificate expiry date. When the certificate expires or is rotated, update the ADP connection in Serval. ### Step 3: Confirm your region and enabled APIs Confirm which ADP region your organization uses and which ADP products or data sets should be available to Serval. *** ## Serval configuration 1. In Serval, go to **Integrations → All integrations → ADP** 2. Click **Connect** | Field | Required | Description | | - | - | - | | **Client ID** | Yes | The Client ID of your ADP API client | | **Client Secret** | Yes | The Client Secret paired with the Client ID | | **Client Certificate** | Yes | The certificate ADP issued or registered for this API client | | **Private Key** | Yes | The private key matching the certificate | | **CA Bundle** | No | Optional certificate authority bundle, if your ADP setup requires one | | **Region** | Yes | Your organization's ADP region | Click **Save**. Before storing anything, Serval: 1. Checks that the certificate and private key are usable together 2. Verifies that ADP accepts the connection A successful save means Serval can authenticate to ADP with the credentials you provided. If validation fails, the error message tells you which part to fix. After connecting, run the built-in health check to confirm Serval can read ADP data available to this connection. *** ## Using ADP in workflows Once connected, workflows can use the **ADP API request** action to read from ADP APIs that your ADP client is allowed to access. Use the ADP documentation available to your organization to choose the right request for your workflow. ADP data can be sensitive. Design workflows to request only the data they need and avoid sending ADP data to places where it should not be stored or displayed. *** ## Troubleshooting ### "The certificate or private key could not be parsed" * Paste the complete certificate and private key values from ADP * Make sure the private key matches the certificate * Avoid stray characters or lost line breaks introduced by copy/paste ### "ADP rejected the credentials" * Verify the Client ID and Client Secret are correct and belong to the same API client * Verify the certificate is the one ADP issued or registered for this API client * Check whether the certificate has expired * Confirm you selected the correct region ### Health check fails after a successful connect Edit and save the connection to re-validate the credentials. If the connection saves successfully but the health check still fails, ask your ADP administrator to confirm this API client has access to the data Serval is trying to read. ### Rotating or renewing the certificate 1. Generate a new certificate and key in ADP API Central, or ask your ADP representative to issue updated certificate material 2. In Serval, open the ADP connection and edit it 3. Paste the new **Client Certificate** and **Private Key**. Fields you leave untouched keep their stored values, so you don't need to re-enter the Client ID or Client Secret 4. Save. Serval re-validates the new material before storing it The optional CA bundle can be replaced on edit but not cleared. To remove a CA bundle entirely, disconnect and reconnect the integration. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your ADP integration. # AlertOps Source: https://docs.serval.com/sections/integrations/alertops Connect AlertOps to Serval with a User API key so workflows can manage alerts, incidents, on-call schedules, escalation policies, and inbound/outbound integrations. ## About AlertOps AlertOps is an incident alerting and on-call management platform. The Serval AlertOps integration connects with a single credential — your AlertOps **User API key** — and gives workflows typed access to every published AlertOps API surface: the modern v2 REST API, the legacy v1 API, and the inbound alert-ingestion endpoint. Serval attaches your key in the right place for each API family automatically (header, query parameter, or request body), so there is nothing technical to configure beyond pasting the key. **Authentication:** API key (an AlertOps User API key, from your AlertOps user profile) **Data sync:** On-demand only. Connecting AlertOps does not import alerts or any other records into Serval, and there are no background syncs — all access happens when a workflow runs an AlertOps action. ## What the AlertOps integration enables | Capability | Description | | - | - | | Alert management (v2) | Create alerts (with escalation policies, topics, priorities, tags, custom fields, recipients, attachments), assign, close, bulk-assign, bulk-close, add notes and messages, read timelines, notifications, and postmortems, and trigger outbound actions on an alert. | | Status-page incidents and services (v2) | Create and update service incidents (investigating → resolved), manage services, components, templates, and subscriber notifications (email, SMS, Slack DM). | | Users and contact methods (v2) | Create, list, update, and delete users, contact methods, notification times, out-of-office records, and custom user attributes, and read a user's roles. | | Groups and topics (v2) | Manage groups, group members, group contact methods, and topics. | | Escalation policies (v2) | Manage escalation policies, member roles, contact-method notification steps, workflows, outbound actions/integrations attached to a policy, and trigger a policy notification directly. | | On-call schedules (v2) | Read and manage group schedules, fixed and rotating schedules, and query who is on call right now (`/api/v2/schedules/oncallnow`). | | Inbound integration configuration (v2) | Create and manage inbound (API/email) integrations programmatically — mappings, filters, alert grouping/delaying rules, escalation-policy overrides, dynamic recipient groups, and enable/disable status. | | Outbound integration configuration (v2) | Create and manage outbound integrations and their methods (templated REST calls AlertOps makes to other systems). | | Maintenance windows, bridges, workflows (v2 + v1) | Manage maintenance windows, conference bridges, and AlertOps workflows (conditions and actions). | | Legacy v1 API | The full legacy surface — RPC-style endpoints like `/api/alert/Create`, `/api/user/ListUsers`, `/api/schedule/Oncallnow`, and inbound-message lookups (`GetAlertIDByInboundMessageID`) — for accounts and scripts still built against v1. | | Inbound alert ingestion | Post events to an AlertOps inbound (API) integration exactly as a monitoring tool would, driving the integration's field mapping and open/update/close rules, via the built-in **AlertOps send inbound alert** action. | The v2 and legacy v1 APIs are exposed as two separate typed actions (**AlertOps API request** and **AlertOps legacy v1 API request**). Prefer v2 — it is RESTful, accepts names where v1 requires numeric IDs, and covers nearly everything — and reach for v1 only where your account's tooling depends on it. ## Get your credentials Sign in to AlertOps and click your username in the top-right corner, then select **Profile**. Find the **API Key** section (shown partially masked) and use **Copy** to copy the full key. The key is tied to your AlertOps user. Results of user-scoped reads (for example listing alerts with the default "view by user" filter) are relative to that user, and the key carries that user's permissions. For team automation, use a dedicated service user rather than a personal account. **Regenerate** in the profile immediately invalidates the old key. If someone regenerates it, workflows start failing with 401s until you paste the new key into the Serval connection. ## Connect in Serval In Serval, open the **AlertOps** integration's connect form. Paste the User API key into the **API Key** field (a masked password field). Submit the form to finish connecting. When you reopen the connection settings, the stored key is shown obfuscated. Saving the form without changing the field keeps your existing key — you only paste a new value when rotating it. ## Verifying the connection The integration ships four health checks, visible on the integration's settings page: 1. **Test AlertOps Connection** — authenticates against the v2 API. 2. **List AlertOps Groups** — confirms group read access. 3. **List AlertOps Escalation Policies** — confirms escalation-policy read access (needed to create alerts). 4. **List Integrations (Legacy v1 API)** — exercises the legacy v1 API's separate query-parameter auth path. If the first three pass but the legacy check fails, v2 workflows still work fine — see the gotchas below. ## Sending alerts into AlertOps Workflows have two ways to raise an AlertOps alert: * **Direct (recommended):** use the **AlertOps API request** action with `POST /api/v2/alerts`, specifying an escalation policy or response play by name. This is fully typed and requires no AlertOps-side setup. * **Through an inbound integration:** use the **AlertOps send inbound alert** action to POST a payload to `https://notify.alertops.com/POSTAlert/{endpointToken}/{source}`, exactly as a monitoring tool would. This drives the inbound integration's field mapping and its "Open / Update / Close Alert When" rules — useful when you want AlertOps-side grouping, delaying, filters, or escalation-policy overrides applied. Create the inbound integration in AlertOps under **Configurations → Integrations → Inbound Integrations → + ADD API**, then copy the endpoint token (the UUID in the generated URL) and the trailing source segment into the action's inputs. Keep the inbound integration's **Method** as `POST` and **Content** as `JSON` (both defaults) — the action sends a JSON POST, and AlertOps also offers GET and form-encoded modes that it cannot drive. Nested payload values are fine: map them on the AlertOps side with the caret syntax (`issue^id`), and array elements as `evalMatches_0^metric`. The inbound endpoint URL embeds its own credential (the endpoint token) — treat the token like a secret. Serval deliberately sends no API key to `notify.alertops.com`. For the same reason, leave the integration's **Authorization Header** option off: Serval's proxy strips `Authorization` headers from workflow requests, so an inbound integration requiring one cannot be driven from a workflow. ## Triggering Serval workflows from AlertOps AlertOps can call Serval when alerts change state (opened, assigned, closed, escalated, SLA thresholds, and any other condition expressible in an AlertOps workflow). This uses Serval's standard webhook trigger — no integration-specific setup: Give your Serval workflow a **Webhook** trigger and copy its trigger URL (`/v2/webhooks/{webhook_id}/trigger`) and secret. In AlertOps, either add a **Send Webhook** action to an AlertOps workflow, or create an **Outbound Integration** with a REST method. Point it at the Serval trigger URL. Add the secret as an `X-Webhook-Secret` header (or a `?secret=` query parameter) on the AlertOps side. If you later rotate the Serval secret, the old one keeps working for its grace window, so update this value before the window ends. Build the JSON body from AlertOps' dynamic fields (for example `<>`, `<>`) — whatever you send becomes the workflow's trigger payload. ## Gotchas and troubleshooting The v2 API documents the User API key from your profile. AlertOps' legacy v1 documentation predates that key and does not state whether older account-level keys differ from it. If only the legacy check fails, your key is valid for v2 but your account's v1 surface may expect a different key — contact AlertOps support if you need v1, or simply use the v2 equivalents (nearly every v1 endpoint has one). `GET /api/v2/alerts` defaults to `viewBy=U` (alerts visible to the key's user). Pass `viewBy: "A"` in the query to list all alerts the account allows, and note its date-range filters (createdFrom/createdTo, closedFrom/closedTo) are capped at six-month windows. Most v2 list endpoints use integer `limit` (max 100) and `offset` with `sortBy`/`sortDir`. `GET /api/v2/alerts` instead uses cursor-style paging: string `limit`, plus `previous`/`next` cursors returned in the response's `metadata` envelope. `/api/v2/alerts` is the alerting/escalation surface (statuses: Open, Assigned, Closed, On Hold, Cancelled; `is_incident` flags major-incident management). `/api/v2/incidents` is the separate status-page surface (Investigating → Resolved) tied to `/api/v2/services` and subscriber notifications. Don't conflate them. AlertOps' published v2 API spec does not describe response bodies, so v2 actions return untyped JSON (a few legacy v1 read endpoints, like listing topics or schedules, are typed). Consult the response examples in the AlertOps API portal ([https://api.alertops.com/help](https://api.alertops.com/help)) when mapping fields in your workflow. AlertOps documents no rate limits. If you build high-volume automation and see 429s or throttling symptoms, add pacing/retries in your workflow design. Regenerating the API key in an AlertOps profile invalidates the old key instantly. Failed runs with 401 errors after someone touched the profile usually mean exactly this — paste the new key into the Serval connection settings. The trailing segment of an inbound endpoint URL is the integration's **Source** value. Editing Source (or clicking Generate next to the URL) invalidates the old URL the moment the Rules drawer is saved — any workflow still passing the old source segment (or old token) to the send-inbound-alert action starts failing immediately. Update the action's inputs whenever someone rebrands an inbound integration. Check the integration's **Inbound Log** in AlertOps (Configurations → the inbound integration → Inbound Log) and look at the message's mapping status. `Pending` can last up to a minute. `Mapping Failed` means the Source/Source Name in the URL and payload didn't match the integration's mapping fields. `Mapped Ignored` means the fields mapped but no alert was generated — either a close event arrived with no matching open alert, or the payload's status value isn't one the integration's Open/Close/Update rules recognize. Also remember the integration's filters may be intentionally dropping the event. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your AlertOps integration. # Amex GBT Neo Source: https://docs.serval.com/sections/integrations/amex-gbt-neo Connect Amex GBT Neo to Serval to automate travel workflows using trip and itinerary data. ## About Amex GBT Neo Amex GBT Neo is American Express Global Business Travel's corporate travel and expense management platform. Connecting Amex GBT Neo to Serval lets your team build workflows that read travelers' trips and itineraries through the Amex GBT **Get Trips API**. This integration uses the Amex GBT developer platform ([developer.amexgbt.com](https://developer.amexgbt.com), with a certification environment at [developer.cert.amexgbt.com](https://developer.cert.amexgbt.com)). Access requires an approved developer app with the Get Trips API enabled. ## What the Amex GBT Neo integration enables | Capability | Description | | - | - | | Trips | List trips (travel itineraries) filtered by date range, traveler, or status | | Trip detail | Retrieve a single trip and its segments (air, hotel, car, rail) by ID | Anything exposed by the Get Trips API for your approved app can be used from Serval workflows. *** ## Amex GBT Neo configuration ### Prerequisites Before connecting Amex GBT Neo, make sure you have: * A registered account on the Amex GBT developer portal * An **approved app** (e.g. `Blackstone-GetTripsApp`) with the Get Trips API enabled * The app's **Client ID** and **Client Secret** * Your Amex GBT API host (the certification host such as `api.cert.amexgbt.com` for testing, or the production host for live data) Serval authenticates with Amex GBT using **OAuth 2.0 client credentials**. It exchanges your Client ID and Secret for a short-lived Bearer access token, then sends it as `Authorization: Bearer ` on each request. You do not need to configure a redirect URL. ### Create an app in the Amex GBT developer portal Register at [developer.amexgbt.com](https://developer.amexgbt.com) (or the certification portal) and sign in. Under **My Apps**, create an app (or open your existing app, e.g. `Blackstone-GetTripsApp`) and request access to the **Get Trips API**. Amex GBT reviews and approves API access for the app. Confirm the Get Trips API shows as enabled before continuing. Copy the app's **Client ID** and **Client Secret**. You will enter these in Serval. Store the secret securely. The portal may not show it again after you leave the app details page. *** ## Serval configuration 1. In Serval, go to **Integrations > All integrations > Amex GBT Neo > Connect** 2. Enter the following information: | Field | Description | | - | - | | API Domain | Your Amex GBT API host, such as `api.cert.amexgbt.com` (cert) or the production host. Omit `https://` and any path. | | Client ID | The app's OAuth **Client ID** | | Client Secret | The app's OAuth **Client Secret** | 3. Click **Save** After connecting, Serval can call the Amex GBT Get Trips API in workflows. You can confirm connectivity with the built-in healthchecks (test connection, list trips). *** ## Additional resources * [Amex GBT Developer Portal](https://developer.amexgbt.com) * [Amex GBT Neo](https://www.amexglobalbusinesstravel.com/neo/) Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Amex GBT Neo integration. # Anthropic Admin Source: https://docs.serval.com/sections/integrations/anthropic-admin Connect Serval to Anthropic's Admin API to manage your Anthropic organization's users, workspaces, and API keys, and to monitor Claude usage and spend. ## About Anthropic Admin The Anthropic Admin integration connects Serval to Anthropic's Admin API so workflows can manage your Anthropic organization: invite and remove users, change organization roles, create and archive workspaces, manage workspace members, audit and disable API keys, and pull usage and cost reports for the Messages API and Claude Code. It is built for Claude-seat admins handling provisioning, off-boarding, key hygiene, and spend monitoring. It covers only the Admin API - calling Claude for message generation is not part of this integration, and regular `sk-ant-api03-` keys will not work. **Authentication:** Admin API key - a single Anthropic Admin API key (starts with `sk-ant-admin01-`) pasted into the connect form. Serval stores it securely and attaches it to every request automatically; workflow code never sees the key. **Data sync:** On demand only. There is no background sync and Serval keeps no copy of your Anthropic data - everything is fetched live from Anthropic at the moment a workflow runs. ## What the Anthropic Admin integration enables | Capability | Description | | - | - | | User management | 7 ready-to-install workflows: List Anthropic Users (pages through all organization users, with an optional exact-email filter), Get Anthropic User by Email, Invite Anthropic User, Update Anthropic User Role, Remove Anthropic User, List Anthropic Invites, and Revoke Anthropic Invite. | | Workspace management | 5 workflows: List Anthropic Workspaces (archived workspaces excluded unless requested), Create Anthropic Workspace, Archive Anthropic Workspace, Add User to Anthropic Workspace, and Remove User from Anthropic Workspace. | | API key management | 2 workflows: List Anthropic API Keys (optional status and workspace filters) and Disable Anthropic API Key (sets the key inactive, immediately revoking access). | | Usage and cost reporting | 5 workflows: Get Anthropic Messages Usage (totals plus day-by-day buckets), Get Anthropic Claude Code Usage (per-actor sessions, commits, PRs, lines changed, and tokens for a single day), Get Anthropic Cost Report, Summarize Anthropic Usage (Last N Days), and Check Anthropic Spend Limit (compares spend against a budget you supply). | | Custom Admin API requests | Custom workflows can reach the full modeled Admin API surface - users, invites, workspaces and members, API keys, and usage and cost reports - with authentication handled automatically. | Anything in the integration's modeled surface of the [Anthropic Admin API](https://docs.claude.com/en/api/administration-api) can be accessed through Serval. ## Get your credentials This integration requires an Anthropic Admin API key, which starts with `sk-ant-admin01-` and is a different credential from the regular `sk-ant-api03-` keys used to call Claude. Only Anthropic organization Admins can create one, in the Anthropic Console. See the [Anthropic Admin API reference](https://docs.claude.com/en/api/administration-api) for background. Sign in at [console.anthropic.com](https://console.anthropic.com/) with an organization Admin account. Open Settings, then Admin Keys - or go straight to the [Admin Keys page](https://console.anthropic.com/settings/admin-keys). Click Create Admin Key and give it a descriptive name, for example Serval Production. The key starts with `sk-ant-admin01-` and is shown only once. Copy it right away and store it in your secret manager. The key is displayed a single time, at creation. If you navigate away without copying it, you will need to create a new one. If you cannot see the Admin Keys page, you are not an organization Admin - ask an org Admin to create the key. ## Connect in Serval In Serval, open the **Anthropic Admin** integration and start a new connection. Paste the full key into the **Admin API Key** field. It is a password field, so the value is hidden as you type. The helper text under the field reads: "Your Anthropic Admin API key (starts with sk-ant-admin01-). Generate one from the Anthropic Console under Settings → Admin Keys." Click **Submit**. The form does not validate the key's format, so a wrong or empty key only surfaces after you submit - you may see "Failed to install integration", or the health check described below will fail. When you reopen the connection settings later, the saved key is shown masked - bullet characters plus its last 4 characters - and it cannot be typed over directly. Only save the settings when you are rotating the key. To rotate, select the pencil icon (or **Replace** button) next to the masked value, paste the complete new `sk-ant-admin01-` key, and save in the same edit. Never save while the key field is empty, and if you opened the settings without meaning to change the key, close them without saving. ## Verifying the connection After you connect, Serval runs the **List Anthropic Organization Users** health check. It uses your stored admin key to list one user in your organization, confirming Serval can reach the Admin API on your behalf. * On success you will see: "Successfully connected to the Anthropic Admin API" * On failure you will see: "Unable to list Anthropic organization users. Please verify your admin API key is valid." The most common cause of failure is pasting a regular `sk-ant-api03-` key instead of an admin key - create an admin key from the [Admin Keys page](https://console.anthropic.com/settings/admin-keys) and update the connection. If the health check is green but a workflow that makes changes (inviting users, archiving workspaces, disabling keys) appears stuck rather than failed, check your pending Serval approvals. Every mutating workflow in this integration defaults to installer approval and waits for sign-off before it runs; read-only workflows run without approval. ## Gotchas and troubleshooting The Admin API requires a key starting with `sk-ant-admin01-`, created under Settings, then Admin Keys, in the Anthropic Console by an org Admin. Regular `sk-ant-api03-` inference keys will not work, and admin keys are only valid for Anthropic's organization-management endpoints. The health check fails immediately with a regular key. On the edit screen the saved key appears masked - bullets plus its last 4 characters - and cannot be typed over directly. To rotate it, select the pencil icon (or **Replace** button) next to the masked value; this clears the field so you can paste the complete new `sk-ant-admin01-` key. Paste the full key and save in one step - do not save while the field is empty. If you change your mind mid-edit, use **Cancel** or close the settings without saving. Update Anthropic User Role supports the organization roles user, developer, billing, claude\_code\_user, and managed. Anthropic's Admin API does not allow promoting a user to admin - do that in the Anthropic Console. Archive Anthropic Workspace cannot be undone through the API, and archiving revokes the workspace's associated API keys. The shipped workflow defaults to installer approval for this reason. The Check Anthropic Spend Limit workflow takes the budget as a workflow input and compares month-to-date (or custom-period) cost against it, returning ok, approaching, or exceeded along with percent used, remaining budget, and a per-day breakdown. It does not read configured limits. Custom workflows can read each member's effective spend limit and period-to-date spend (`GET /v1/organizations/spend_limits/effective`) and set or remove a per-user override (`POST /v1/organizations/spend_limits`, `DELETE /v1/organizations/spend_limits/{spend_limit_id}`). These endpoints exist only for Claude Enterprise (claude.ai) organizations and require a scoped Admin API key created in claude.ai under Organization settings → API with the `read:spend_limits` and `write:spend_limits` scopes; a Console `sk-ant-admin01-` key returns an error or an empty list. See Anthropic's [Spend Limits API guide](https://platform.claude.com/docs/en/manage-claude/spend-limits-api). An admin key can remove users, archive workspaces, and disable other API keys across your whole organization. Treat it as the most sensitive credential in your stack and rotate it regularly. Mutating workflows ship with installer approval as the default approval procedure; read-only workflows ship with no approval. Only the Admin API surface (organization, workspace, and API key management, plus usage and cost reporting) is covered. Calling Claude for message generation is handled elsewhere, not through this integration. Get Anthropic Claude Code Usage fetches one UTC day at a time (YYYY-MM-DD). For ranges, use Get Anthropic Messages Usage, Get Anthropic Cost Report, or the Summarize Anthropic Usage (Last N Days) workflow. Every request Serval sends to Anthropic automatically carries the pinned API version `2023-06-01` alongside your key, and the key is only ever sent to `api.anthropic.com`. Workflow authors never set authentication headers themselves. See [Anthropic API versioning](https://docs.claude.com/en/api/versioning) for what the version controls. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Anthropic Admin integration. # Apple Business Manager Source: https://docs.serval.com/sections/integrations/apple-business-manager Connect Apple Business Manager to Serval to assign devices to MDM servers, sync your Apple device fleet into asset management, and call any Apple Business Manager API endpoint from workflows. ## About Apple Business Manager Apple Business Manager (ABM) is Apple's portal for IT administrators to deploy and manage Apple devices, apps, and Managed Apple Accounts at scale. Serval connects to the Apple Business Manager API using an ABM API account, so your workflows can assign or unassign devices to MDM servers, ingest your organization's devices into Serval asset management, and reach anything else Apple's Business Manager API offers. No browser sign-in is involved - the connection runs entirely on credentials you create inside Apple Business Manager. **Authentication:** ABM API account (Client ID + Key ID + EC private key). Each time Serval calls Apple on your behalf, it signs a short-lived token with your private key and exchanges it with Apple for access - and what the integration can do is governed by the API account's role in ABM. **Data sync:** On-demand. The shipped "Ingest Computers from Apple Business Manager" workflow pages through your organization's devices, looks up each device's AppleCare coverage, and syncs both into Serval asset management; everything else runs only when a workflow calls it. There is no other background sync. ## What the Apple Business Manager integration enables | Capability | Description | | - | - | | Generic API access | Make any request to the Apple Business Manager API (read or write) from a workflow, with optional query parameters and body. | | Assign or Unassign Device in Apple Business Manager | Shipped workflow: assigns or unassigns one or more devices (comma-separated serial numbers) to an MDM server matched by display name, and returns the activity ID, status, and a summary. Requires installer approval by default. | | Ingest Computers from Apple Business Manager | Shipped ingestion workflow: fetches all organizational devices (following Apple's pagination automatically), looks up each device's AppleCare coverage, and syncs them into Serval asset management as computers. Optional inputs point the first page at a different devices endpoint and turn the coverage lookup off. Runs without approval by default. | | Connection health check | Built-in test that exercises the full authentication chain by fetching a single device from your organization. | Anything defined in the [Apple Business Manager API](https://developer.apple.com/documentation/applebusinessapi) can be accessed through Serval. ## Get your credentials You need an **API account** in [Apple Business Manager](https://business.apple.com) with a generated private key. Only users with the **Administrator** role in ABM can create API accounts. Apple's official guide: [Create an API account in Apple Business Manager](https://support.apple.com/guide/apple-business-manager/create-an-api-account-axm33189f66a/web). Go to business.apple.com and sign in with an **Administrator** account. Click your name at the bottom of the sidebar, select **Preferences**, then select **API**. Click **Get Started**, enter a name for the account (e.g. "Serval Integration"), then click **Create**. Click **Generate Private Key** to download the .pem private key file. Click **Manage** to view the **Client ID** and **Key ID** - you need both, plus the contents of the .pem file, for Serval. The .pem private key downloads **exactly once**, at generation time. Store it securely. If you lose it, you must generate a new key in ABM - which gets a new Key ID - and update Serval with both. The key Apple generates is an EC P-256 key, which is exactly what Serval requires. Don't substitute a key from another system - RSA keys are rejected. ## Connect in Serval All three fields are required - the form won't accept a blank value for any of them. **Client ID**. Helper text: "Your Apple Business Manager Client ID (format: BUSINESSAPI.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)". **Key ID**. Helper text: "Your Apple Business Manager Key ID". It's shown next to your key in ABM under Preferences → API → Manage. **Private Key** (multiline password field). Helper text: "Paste the contents of your .pem private key file". Paste the **entire** file, including the "-----BEGIN PRIVATE KEY-----" and "-----END PRIVATE KEY-----" lines, with no extra whitespace. Submit the form, then run the connection health check (below). Serval doesn't parse the key when you save - a bad paste only surfaces when the connection is tested or used, so always run the health check after connecting. **Editing an existing connection:** Client ID and Key ID must stay filled in - an update without either is rejected. The Private Key field shows a read-only masked value (bullets plus the last 4 characters of the stored key) with a **Replace** button; save without clicking **Replace** and your stored key is kept unchanged. To rotate the key, click **Replace** and paste the entire contents of the new .pem file. ## Verifying the connection The integration ships one health check: **Test Apple Business Manager Connection** - requests a single device from your organization through Serval, verifying the full chain: private key parsing, token signing, the token exchange with Apple, and an authenticated API call to Apple Business Manager. * On success: "Successfully authenticated with Apple Business Manager and retrieved device data" * On failure: "Unable to connect to Apple Business Manager. Please verify your Client ID and private key are correct. Common issues: invalid EC P-256 private key format, incorrect Client ID, or insufficient API permissions." A green health check proves authentication works - it does not prove your API account can do everything your workflows need. Serval configures no scopes of its own; permissions come entirely from the API account's role inside Apple Business Manager. If the test passes but a workflow fails, check the API account's permissions in ABM first. ## Gotchas and troubleshooting Serval requires the exact key type that ABM's **Generate Private Key** produces. Paste the entire .pem contents including the "-----BEGIN PRIVATE KEY-----" and "-----END PRIVATE KEY-----" lines, with no extra whitespace. A malformed paste fails with an error that includes "failed to decode PEM block: ensure the private key starts with '-----BEGIN PRIVATE KEY-----' and ends with '-----END PRIVATE KEY-----'". RSA or other key types fail with "private key is not EC format (Apple Business Manager requires an EC P-256 key)". These errors appear when the connection is tested or used - not when you save the form - so run the health check right after connecting or rotating the key. Updates re-validate Client ID and Key ID, so both must be present whenever you save changes. The Private Key field shows a read-only masked value with a **Replace** button; saving without replacing it keeps the stored key. To rotate, click **Replace** and paste the complete new .pem contents. Serval doesn't validate the new key at save time, so a partial or wrong paste only shows up when the connection is next used - re-run the health check after every rotation. Connections created before Key ID support stored only a Client ID. These fail with an error that includes "Apple Business Manager integration is missing Key ID, please reconfigure with your Key ID from Apple Business Manager → Preferences → API". Fix by editing the connection and adding the Key ID (re-paste the private key only if you're also rotating it). ABM only offers the .pem at generation time. If it's lost, generate a new key in ABM - it gets a **new Key ID** - and update the Serval connection with both the new Key ID and the new key. The Key ID must always match the private key in use. Serval installs this integration with no scopes of its own; access tokens are requested with Apple's fixed "business.api" scope. What the integration can actually read or change is governed by the API account's role and permissions inside Apple Business Manager. If calls are denied despite a passing health check, adjust the API account in ABM. The generic API action is a raw wrapper around Apple's Business Manager API with no built-in endpoint catalog. There is no separate field for path parameters: build the final path string yourself before sending. A path still containing a literal `{param}` placeholder is sent to Apple unmodified and will fail. Apple only exposes coverage per device, so the ingestion workflow makes one additional request for every device on each page. Each synced device carries `appleCareCoverage` - the active record ending last (an open-ended AppleCare+ for Business subscription ranks above any dated plan), or the most recently ended record when nothing is active - with `status`, `paymentType`, `description`, `startDateTime`, `endDateTime`, `isRenewable`, `isCanceled`, `contractCancelDateTime` and `agreementNumber`, plus the full history in `appleCareCoverages`. Map `appleCareCoverage.endDateTime` to your asset's warranty expiration field. A device whose lookup fails (for example an API account without coverage access) still syncs, without those keys, and the run log says how many lookups failed. Turn **Include AppleCare coverage** off in the workflow inputs to skip the lookups entirely. The "Assign or Unassign Device in Apple Business Manager" workflow looks up your MDM servers and matches the target by display name (case-insensitive). If no server matches, the workflow errors and lists the available server names - copy the name exactly as it appears in that list. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Apple Business Manager integration. # Connect a Custom Application Source: https://docs.serval.com/sections/integrations/application Connect any application with an HTTPS API to Serval - even apps that aren't in the catalog - and use it in workflows with authentication handled for you. ## About custom applications Serval can connect to any application that exposes an HTTPS API, even if it isn't in the [integration catalog](/sections/integrations/overview). You create the application once, store its API credentials with Serval, and from then on workflows can call its API with authentication injected automatically - the same pattern the native integrations use, pointed at your own tool. Custom applications carry the **Access** and **Workflows** capabilities: workflows can call the app's API, and you can manage access to the app (resources, roles, and access policies) just like any other connected application. **Authentication:** an API key or token (sent in a header you choose), OAuth 2.0 client credentials (Serval exchanges a Client ID and Secret for tokens automatically), OAuth 2.0 JWT Bearer (Serval signs a JWT and exchanges it for an access token), or per-user sign-in through a configured OpenID Connect (OIDC) provider. **Data sync:** on demand. Workflows call the app's API when they run; there are no background syncs for custom applications. ## What a custom application enables | Capability | Description | | - | - | | Workflow automation | Workflows (and Catalyst) call the app's API through Serval's built-in HTTP API request action - the workflow specifies what to do, and Serval fills in the base URL and authentication. | | Secure API proxying | Credentials are stored encrypted, never shown back in clear text, and injected server-side on every request. Workflow authors never see or handle them. | | Access management | Define the app's resources and roles, and manage access to them with Serval's access policies and requests - the same as any catalog integration. | | Multiple instances | One application definition can have multiple instances (for example, a production and a sandbox tenant), each with its own credentials. | ## Get your credentials Credentials come from the application you're connecting - check its developer or admin documentation for one of these: * **An API key or token** - most tools issue these from a settings or developer page. Note which header the tool expects (a Bearer token, Basic auth username/password, an X-API-Key header, or a custom header name - Serval supports all four). * **OAuth client credentials** - a Client ID and Client Secret plus the token endpoint URL, usually listed in the tool's API documentation. This is the machine-to-machine variant of OAuth (no browser sign-in). * **JWT Bearer credentials** - an RSA private key, issuer (usually a service account ID), token endpoint URL, and audience. The provider must support the OAuth JWT Bearer authorization grant with RS256 signing. Also note the API's **base URL** (for example, [https://api.example.com](https://api.example.com)) - the root URL for API requests, without any path. ## Connect in Serval Connecting happens in two stages: create the application, then configure how it authenticates. ### Create the application In your team workspace, go to **Integrations → Connect new**. The **Connect an app** card is the first card in the grid - anything you've typed in the search box pre-fills the application name. Click the card to open the **Connect an application** dialog: * **Application Name** (required) - typically the tool's name. * **Domain** (required) - the company's web domain (for example, "tool.com"), entered without a scheme; the field shows the "https\://" prefix for you. Serval uses it to fetch the app's logo automatically. * **Instance Name** (optional) - "This name helps distinguish multiple instances of the same app." Click **Create**. Serval creates the application and takes you straight to its page. If an application with the same service and instance name already exists, you'll see "an app for this service with this name already exists" - pick a different instance name. ### Configure API authentication On the application's page, open the **API Integration** section ("Connect this application to an external API using an API key or OAuth credentials.") and choose an **Authentication Method**: "Connect using an API key or token." The root URL for API requests, without any path - for example, [https://api.example.com](https://api.example.com). Must start with https\://. Each header card has an **Authorization Method** selector with a live preview of the header Serval will send: * **Bearer Token** - paste your token; sent as an Authorization header with the "Bearer" prefix. * **Basic Auth** - enter the **Username** and **Password**; "Your username and password will be base64-encoded automatically." * **X-API-Key** - paste your key; sent as an X-API-Key header. * **Custom Header** - set the **Custom Header Name** (for example, "X-Custom-Auth") and the **Header Value** - any header name the tool expects. Use **Add Header** if the API needs more than one authentication header. Click **Save Credentials**. A green **Connected** badge appears once the credentials are stored. "Connect using a Client ID and Secret." This is the OAuth 2.0 client credentials grant - Serval mints and refreshes access tokens for you. The root URL for API requests, without any path. Must start with https\://. "The OAuth token endpoint - usually found in your API provider's developer docs." For example, [https://api.example.com/oauth/token](https://api.example.com/oauth/token). Must start with https\://. "Found in your OAuth application or API settings." After saving, the secret is shown masked (its last four characters) with a **Replace** button - it is never displayed in full again. Specify the OAuth scopes needed for this integration, if the API requires them. Some providers require extra parameters in the body of the OAuth token request (for example, a tenant identifier). Add them as key/value rows and Serval includes them in the body of every token request. Leave this empty if your provider doesn't need it. Some APIs require a static header on every request in addition to the OAuth access token (for example, a separate API key). Add them under **Custom headers** as name/value rows, and Serval sends them alongside the token on every API request. You can't name a header `Authorization` here, since Serval sets that automatically from the OAuth token. Click **Save Credentials**. A green **Connected** badge appears once the credentials are stored. Select **OAuth 2.0 — JWT Bearer** for APIs that exchange a signed JWT for an access token. 1. Enter the **API Base URL** and HTTPS **Token URL**. 2. Enter the **Issuer (service account ID)** and **Audience** required by the provider. 3. Paste an unencrypted RSA **private key** in PEM format (at least 2048 bits). The **Subject** defaults to the issuer; override it if the provider requires a different principal. Add a **Key ID** or **Scopes** only if the provider requires them. 4. Save the connection. Serval signs short-lived RS256 assertions and obtains access tokens automatically when requests need them. For [Serraview Core API](https://knowledge.eptura.com/Serraview/Integrations/Serraview_Core_API/Serraview_Core_API_Overview/Access_Serraview_Core_API), use your instance's `https://[instance].serraview.com/oauth2/token` as both **Token URL** and **Audience**, the Serraview service account ID as **Issuer**, and its RSA private key. Leave the optional fields blank unless your administrator specifies otherwise. Test with a workflow request to `/api/v2/whoami`. When editing a saved connection, leave the private-key field blank to keep the stored key, or paste a replacement to rotate it. The key is encrypted and is never sent to the token endpoint. Serval sends the signed JWT using the `urn:ietf:params:oauth:grant-type:jwt-bearer` grant. This option does not implement `private_key_jwt` client authentication or RFC 8693 token exchange. Saved secrets are encrypted and never returned to the screen - you'll see a masked value with a **Replace** button. To rotate a credential, click **Replace** and paste the new value; leaving a stored secret untouched while editing other fields keeps it unchanged. To remove authentication entirely, use **Clear Credentials** (it asks for confirmation). ## How workflows use it ### Reuse your OIDC sign-in When multiple custom integrations in the same team use the same OIDC provider, Serval reuses your existing sign-in when the credential covers the required resource and permissions. Click **Connect account** to attach your account to another integration. If your existing credential is compatible, you don't need to sign in again. Workflows you start for yourself also reuse a compatible sign-in automatically, without requiring you to click **Connect account** for each integration. Each user connects their own account. When a workflow requires additional authorization, its connection prompt lists the required catalog and custom integrations together. Serval refreshes shared credentials automatically when the provider supports refresh tokens. Reconnecting replaces the credential for integrations already sharing that credential. Other integrations that have separate credentials keep them. Removing one integration preserves the credential while another integration still uses it. You may need to sign in again when the provider or OAuth client changes, an integration requires a different resource or additional permissions, or your provider rejects the refresh token. If a shared credential expires without a refresh token, **Connect account** starts a new sign-in. The upgrade preserves your existing connections and credentials. An older sign-in may remain specific to its existing integration until you sign in again to enable sharing. ### Call the API Once credentials are saved, workflows call the application through Serval's built-in **HTTP API request** action. The workflow (or Catalyst, when it builds one for you) specifies the request - the path, method, and any parameters - and Serval automatically applies your configured base URL and injects the stored authentication. Workflow authors never handle credentials, and requests only ever go to the base URL you configured. ## Verifying the connection Custom applications don't have the prebuilt health checks that catalog integrations ship with. To confirm everything works end to end: 1. Check for the green **Connected** badge in the API Integration section - it confirms the credentials are stored. 2. Run a quick test workflow that makes a simple read request against the API (your Serval team or Catalyst can set one up in a couple of minutes). A successful test request proves the base URL, authentication, and the app's permissions all work together. ## Gotchas and troubleshooting The API Base URL and Token URL must start with https\:// - the form and the backend both reject anything else. Plain http\:// APIs cannot be connected. OIDC sign-in is shared only when integrations use the same provider, OAuth resource, and compatible permissions within the same team. Additional permissions, a different resource, or a rejected credential can require authorization again. Use **Reconnect** to explicitly sign in again. The API Base URL should be the API's root (for example, [https://api.example.com](https://api.example.com)), not a full endpoint path. Workflow requests supply the path - if the base URL already contains part of the path, requests can end up doubled or misrouted. Creating an application with the same name and instance name as an existing one fails with "an app for this service with this name already exists". Use the **Instance Name** field to distinguish multiple instances of the same tool. With multiple authentication headers, you can rotate one header's value on its own: click **Replace** on that header, enter the new value, and leave the others untouched. Adding, removing, or renaming a header while keeping other stored values is rejected with "Adding, removing or renaming a header means re-entering every header value. Click 'Replace' on each existing header." In that case, have every header's value on hand before editing. Each header name can be used only once; duplicates are rejected. After saving, credentials display as a masked value with the last four characters visible. There is no way to reveal a stored secret - if you've lost the original, generate a new one in the third-party tool and click **Replace** in Serval. Re-check the header type against the tool's API documentation - the most common mismatch is a token pasted as a Bearer Token when the API expects X-API-Key (or vice versa), or a missing second header on APIs that require two. The **Authorization Method** preview in the form shows exactly what Serval will send. *** ## Programmatic access (API) You can also create and manage applications programmatically using the Serval API. This is useful for: * Automating the creation of applications as part of your infrastructure-as-code * Building integrations that programmatically manage app connections * Syncing applications from external systems ### Understanding the data model When using the API, it's important to understand that applications consist of two separate resources: * **Custom Service**: Represents the third-party application definition (e.g., "Internal HR System"). It stores the service name and domain for branding purposes. * **App Instance**: Represents a specific installation/connection of a service that appears on your Integrations page. Each Custom Service can have multiple App Instances. **Important:** Creating a Custom Service alone does **not** create a usable application. You must also create an App Instance linked to the Custom Service. Only App Instances appear on your Integrations page in Serval. When you create an application through the UI, Serval automatically creates both resources for you. When using the API, you must create both separately. ### API Endpoints Create, read, update, and delete Custom Services (the underlying app definition). Create App Instances linked to Custom Services using the `customServiceId` parameter. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with connecting your application. # Asana Source: https://docs.serval.com/sections/integrations/asana Connect Asana to Serval with a Personal Access Token so workflows can read and write tasks, projects, portfolios, and goals on demand. ## About Asana Asana is a work management platform for tasks, projects, portfolios, and goals. Serval connects to Asana using an Asana Personal Access Token (PAT), which is stored as the connection's API key and attached securely to every request Serval sends to Asana. The integration gives workflows on-demand access to the entire Asana API through a single, fully typed action, so Serval can look up or change any Asana record your token can reach. No workflows are pre-installed when you connect. **Authentication:** API key (Asana Personal Access Token). There is no OAuth flow and no Serval-requested scopes - the token carries exactly the Asana permissions of the user who created it. **Data sync:** On-demand only. There is no background sync, scheduled ingestion, or webhook listener - Serval talks to Asana only when a workflow runs an Asana action. ## What the Asana integration enables | Capability | Description | | - | - | | Full Asana API access | A single "Asana API request" action covers the entire Asana API surface - 192 typed operations generated from Asana's official specification - so workflows can read and write any Asana record from one connection. | | Manage tasks | Read, create, update, and delete tasks, including assignees, due dates, custom fields, followers, and subtasks. | | Manage projects and portfolios | Work with projects, portfolios, portfolio items, custom field settings, and memberships. | | Manage goals | Read and update goals, goal relationships, metrics, and followers. | | Look up users and workspaces | List and read users, workspaces, and workspace memberships. | | Handle large lists | Asana returns long lists one page at a time; workflows follow Asana's next-page marker to retrieve every item. | Anything defined in the [Asana API](https://developers.asana.com/reference/rest-api-reference) can be accessed through Serval. ## Get your credentials Serval needs an Asana Personal Access Token. Create it as a user whose Asana permissions cover every workspace, project, and task your workflows need to reach - the token can see exactly what that user can see, nothing more. Asana's official guide is [here](https://developers.asana.com/docs/personal-access-token). In Asana, click your profile picture in the top right corner and select **Settings**. Open the **Apps** tab, scroll to the **Build new apps** section, and click **View developer console**. You can also go directly to the [Asana developer console](https://app.asana.com/0/my-apps). Click **Create new token** and give it a descriptive name, such as "Serval Integration". Click **Create token** and copy the Personal Access Token right away. Asana shows the token only once, at the moment of creation. If you navigate away without copying it, you will need to create a new token. Because the token inherits its creator's Asana permissions, create it as a user with access to everything your workflows will touch. If that user's access changes later, recreate the token. ## Connect in Serval In your team workspace, go to **Integrations**, choose **Asana** from the catalog, and start a new connection. The **Configure Asana** dialog opens with two fields. **Instance Name** is a human-readable label for this connection inside Serval. It does not affect which Asana workspace the token reaches. The same field appears again, pre-filled, on the connection's settings page. Paste the Asana Personal Access Token into the **API Key** field. It is a password-style field, so the value is hidden as you type. The form does not mark this field as required, but the connection cannot authenticate without it. Click **Submit**. After saving, the API Key is displayed obfuscated - bullet dots with only the last 4 characters visible - and can be replaced later but never viewed in full. There are no field-level validation messages on this form - a typo in the token will not be caught at save time. It will surface later as failed workflow runs, so paste carefully. When editing an existing Asana connection - including simply renaming it - always re-enter the full Personal Access Token in the **API Key** field before saving. Do not clear pre-filled fields, and do not save while the API Key still shows only its masked value. When rotating tokens, paste the new token and save in one step. ## Verifying the connection Asana does not surface named health checks in Serval - the **Health Checks** section that appears on some integrations' settings pages is not shown for Asana, and there is no built-in connection test with success or failure messages. The most direct way to confirm the connection works end to end is to run a quick read-only workflow against Asana - for example, one that looks up the users in your workspace - and check that it returns data. Your Serval team or Catalyst can set one up in a couple of minutes. If a workflow fails or returns empty results even though the token was pasted correctly, the most common cause is permissions: the user who created the token cannot see the workspace, project, or task the workflow is targeting. Recreate the token as a user with access to that data, then replace it in the connection's API Key field. ## Gotchas and troubleshooting When saving any change to an existing Asana connection - for example renaming it or rotating credentials - always re-enter the full Personal Access Token in the API Key field before submitting. Do not clear pre-filled fields, and do not save the form while the API Key shows only its masked placeholder. When rotating tokens, paste the new token and save in one step. There are no scopes. If the user who created the token cannot see a workspace, project, or task, neither can Serval - requests are denied or come back empty. Create the token as a user with access to everything your workflows touch, and recreate it if that user's access changes. The Personal Access Token is displayed a single time at creation. If it is lost or revoked, create a new token in the Asana developer console and replace the connection's API Key value. Serval attaches your token only to requests going to Asana's official API at app.asana.com. The Asana API request action already targets that address automatically, so this is handled for you - but requests to any other destination are never authenticated with this credential. Asana does not return every item at once. Each response includes a next-page marker, and a workflow must pass that marker back on the following request, repeating until no marker remains. Workflows that skip this step only ever see the first page of results. Asana nests both single records and lists inside a wrapper object named "data", and by default returns compact records that include only a handful of fields. If a workflow gets a record back but key details are missing, it usually needs to request those fields explicitly via Asana's optional-fields setting. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Asana integration. # Ashby Source: https://docs.serval.com/sections/integrations/ashby Ashby is an all-in-one recruiting platform (ATS) - connect it to Serval with an Ashby Admin API key and your workflows can automate candidates, jobs, interviews, offers, and the rest of the Ashby API. ## About Ashby Ashby is an all-in-one recruiting platform covering applicant tracking, interview scheduling, sourcing, and hiring analytics. The Serval integration stores an Ashby Admin API key and uses it to call the Ashby API on behalf of your workflows - listing candidates, creating jobs, managing offers, and everything in between. Your key is only ever sent to Ashby's own API. **Authentication:** API key. You paste an Ashby Admin API key once; Serval stores it and attaches the correct authentication to every Ashby request automatically. **Data sync:** on demand. There are no background syncs and no webhook ingestion on Serval's side - Serval calls Ashby only when a workflow runs. ## What the Ashby integration enables | Capability | Description | | - | - | | Workflow automation | The **Ashby API request** action gives workflows typed access to the full Ashby API - 164 endpoints covering candidates, applications, feedback, interviews, schedules, jobs, job postings, job boards, offers, openings, departments, locations, custom fields, surveys, assessments, referrals, sources, users, reports, and webhooks. | | List Candidates workflow | A ready-to-install workflow that lists every candidate in your organization, with built-in support for paging through large candidate lists. Runs without approval by default. | | Create Candidate workflow | A ready-to-install workflow that creates a candidate from a name (required) plus optional email, phone number, website, LinkedIn, GitHub, and Twitter links. Requires installer approval by default. | | AI workflow building | [Catalyst](/sections/documentation/catalyst/overview) knows the full Ashby endpoint catalog and request/response shapes, so it can draft Ashby automations for you. | Anything defined in the [Ashby API](https://developers.ashbyhq.com/reference) can be accessed through Serval. ## Get your credentials You need an Ashby Admin API key whose permissions cover the endpoints your workflows will call. The full endpoint catalog is in the [Ashby API reference](https://developers.ashbyhq.com/reference). Sign in at [app.ashbyhq.com](https://app.ashbyhq.com). You need admin permissions - if you don't see the API Keys option in the next step, contact your Ashby administrator. Navigate to **Admin → Integrations → [API Keys](https://app.ashbyhq.com/admin/api/keys)**. Click **+ New** to open the API key setup wizard and enter a descriptive name (for example, "Serval Integration"). Optionally select an Integration Partner. New Ashby API keys start with **no permissions at all**. A key with missing permissions saves fine in Serval but fails later when a workflow runs. Use the checkboxes to grant read and/or write access per module. Hover the **i** icon next to each module to see exactly which endpoints it covers, and optionally enable access to confidential jobs. Grant what your workflows will actually use - for example, Candidates **read** for List Candidates and Candidates **write** for Create Candidate. Click **Save and Continue**, then copy the API key and store it securely. Anyone with the key can act within its granted permissions. ## Connect in Serval In Serval, open the Ashby integration and start a new connection. The connect form has two fields. A display name that identifies this Ashby connection inside Serval (for example, "Ashby"). The same field appears again, pre-filled, on the connection's settings page, so the name can be changed later if needed. Paste the Ashby Admin API key **exactly as Ashby shows it** - Serval builds the authentication header for you, so don't encode the key or add any prefix. The field is a password input; after saving, it displays as bullets with only the last 4 characters visible. Submit the form. Neither field is validated, and Serval does **not** test the key against Ashby at this point - a typo won't surface until a workflow runs (see "Verifying the connection" below). If the save itself fails, you may see "Failed to connect service", "Failed to install integration", or "Failed to save configuration. Please try again." depending on where you connected from - these mean the form didn't save, not that the key is bad. ## Verifying the connection This integration ships **no automatic health checks**, and connecting does not test your key against Ashby. To confirm everything works end to end, install and run the **List Candidates** workflow right after connecting: * If it returns your candidates, the key and its Candidates read permission are working. * If it fails with an authentication or permission error, re-enter the API key in full (raw key, no prefix) and check the key's module permissions in Ashby. An under-permissioned key can look healthy and still fail on specific actions - a key that lists candidates fine will still fail to create one if the Candidates module only has read access. When one workflow works and another doesn't, check that module's read/write grants in the Ashby key wizard first. ## Gotchas and troubleshooting Saving the connect form stores the credentials without calling Ashby, and there are no automatic health checks. An invalid or under-permissioned key surfaces as an error the **first time a workflow calls the Ashby API**, not at connect time. Run a quick workflow (such as List Candidates) immediately after connecting to verify. Ashby keys grant nothing by default. In the key wizard, enable read and/or write per module to cover every endpoint your workflows call. A missing module permission shows up as an API error at workflow run time. Serval builds the authentication for you. Do not encode the key or add any prefix - paste it exactly as Ashby displays it. A modified key fails on the first workflow run. On the integration settings page, the saved key shows as an obfuscated value with a small pencil (edit) icon next to it. Click the pencil, paste the complete new key into the input (placeholder: "Enter new value"), and click **Update**. In the reconnect dialog, the same field shows a **Replace** button instead - click it and paste the full new key there. Either way, always paste the entire key: do not clear a pre-filled field and submit, and whenever you edit anything about the connection, re-enter the API key in full as part of the same save. If the connection misbehaves after an edit, re-enter the API key and save again. If the update itself fails, the settings page shows "Failed to update configuration", and the reconnect dialog shows "Failed to update integration:" followed by error details. The Instance Name field appears pre-filled on the connection's settings page. To rename the connection, change it there - and, as with any edit, re-enter the API key in full as part of the same save. Ashby's API uses POST requests for everything - even reads. The operation name is part of the request address, not the method. Workflows that try to use GET will not match the Ashby schema. Ashby list operations return results a page at a time, with a flag indicating more data is available and a cursor for the next page. Workflows should keep requesting with the returned cursor until no more data remains - the shipped List Candidates workflow accepts cursor and syncToken inputs for exactly this. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Ashby integration. # AWS Source: https://docs.serval.com/sections/integrations/aws Amazon Web Services (AWS) is a public-cloud platform for compute, storage, identity, and more - Serval connects to your AWS accounts through a cross-account IAM role to run workflows across EC2, IAM, S3, Route 53, and the other supported AWS services. ## About AWS Amazon Web Services (AWS) is a public-cloud platform offering on-demand compute, storage, database, identity, and networking services. The Serval AWS integration is multi-product: connecting an AWS account once gives your workflows access to every supported AWS service (see the capability table below) - limited only by the permissions on the IAM role you delegate. Each connected AWS account is its own app instance keyed by its 12-digit account ID, so multi-account organizations connect each account individually and workflows can target one account or all of them. **Authentication:** Cross-account IAM role assumption (STS AssumeRole with an External ID). Serval never stores long-lived AWS keys - only your Role ARN and a Serval-generated External ID, exchanged at runtime for short-lived 15-minute session credentials. **Data sync:** No user or identity sync. The only background sync ingests IAM roles tagged with the key "serval" (including their inline and attached policies) to power temporary role access; everything else is on-demand from workflows. ## What the AWS integration enables | Capability | Description | | - | - | | API actions across the supported AWS services | Workflows can call any operation of Auto Scaling, CloudWatch, CloudWatch Logs, EC2, EKS, Elastic Load Balancing v2, IAM, Identity Store, Lambda, Organizations, RDS, RDS Data, Resource Groups Tagging, Route 53, S3, SSO Admin, and Workspaces - for example listing IAM roles, describing EC2 instances, listing S3 buckets, changing Route 53 DNS record sets, or listing Organization accounts. Access is gated entirely by your IAM role's permissions. | | IAM role creation helper | A guided multi-step action that validates your inputs, creates an IAM role with the trust policy you supply, applies optional tags, and attaches an inline policy named after the role. | | IAM role resource sync | Ingests IAM roles tagged "serval", along with their inline and managed policy documents, so they can be granted through Serval's temporary role-access feature. | | Pre-built workflows | Two installable workflows ship with the integration: "Create AWS IAM Role" (requires installer approval by default) and "List AWS Organization Accounts" (no approval by default). | | Multi-account targeting | Each AWS account connects separately. Workflows can pin a specific account by its 12-digit ID or fan out across every connected account, and the account ID is available to workflows at runtime. | | Temporary (JIT) role access | Serval can grant users time-boxed sessions on ingested AWS roles. Setup is covered on the [AWS Role Ingestion](/sections/integrations/aws-role-ingestion) page; access-policy configuration is on the [AWS Role Access page](/sections/access-management/configuration/aws-role-access). | Anything defined in the [AWS API](https://aws.amazon.com) for the services in the table above can be accessed through Serval. Route 53 is a global service: its requests still take the `region` argument - pass `us-east-1`. ## Get your credentials Serval connects to AWS by assuming an IAM role in your account, following AWS's standard pattern for [delegating access to another AWS account](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user.html). You create the role, tell it to trust Serval's AWS account for your region with an [External ID](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html), and attach whatever permission policies your workflows need - Serval mandates no permissions of its own. Each Serval region runs in its own AWS account, so the account your role trusts depends on where your organization is hosted. Check the address you sign in at, and ask [support@serval.com](mailto:support@serval.com) if you're unsure which region you're on. | Serval region | Sign-in address | Serval AWS Account ID | | - | - | - | | United States (US1) | `app.serval.com` | `992382851720` | | European Union (EU1) | `app.eu1.serval.com` | `311208284913` | | Self-hosted | Your own address | The AWS account your Serval worker runs in (confirm it with your Serval contact) | In Serval, go to **Integrations → All integrations → AWS → Connect** and leave the dialog open. It displays the **Serval AWS Account ID** for your region and your team's **External ID**. Copy both: the trust policy you create next must name that account ID, which matches your region's row in the table above. Self-hosted deployments trust the account their own worker runs in, not the value shown in the dialog. In the AWS console, go to **IAM → Roles → Create role** and choose **Another AWS account** as the trusted entity. Enter the Serval AWS Account ID for your region from the table above, tick **Require external ID**, and paste the External ID from the dialog. Attach the policies that grant the actions you want Serval to perform - for example, IAMReadOnlyAccess for read-only IAM workflows. The role's policies define exactly which AWS APIs Serval can call. Name the role and click **Create role**. Open the new role, go to **Trust relationships → Edit trust policy**, and add an `sts:TagSession` statement alongside the existing `sts:AssumeRole` statement. Both statements use the Serval account principal; keep the `sts:ExternalId` condition on the AssumeRole statement. Pick the tab for your region and replace `` (including the angle brackets) with the External ID shown in the Connect AWS dialog: ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::992382851720:root" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "" } } }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::992382851720:root" }, "Action": "sts:TagSession" } ] } ``` ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::311208284913:root" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "" } } }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::311208284913:root" }, "Action": "sts:TagSession" } ] } ``` Replace `` with the AWS account your Serval worker runs in. ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam:::root" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "" } } }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam:::root" }, "Action": "sts:TagSession" } ] } ``` Copy the Role ARN and your 12-digit AWS account ID, then return to the Connect AWS dialog in Serval. The External ID is deterministic per Serval team - it never changes across reconnects, so it's safe to hardcode in Terraform-managed trust policies. If you want Serval to run the connection health checks and ingest roles for temporary access, include `iam:ListRoles` (connection check), `organizations:ListAccounts` (Organizations check), and the IAM read actions `iam:GetRole`, `iam:ListRolePolicies`, `iam:GetRolePolicy`, `iam:ListAttachedRolePolicies`, `iam:GetPolicy`, and `iam:GetPolicyVersion` (role ingestion) in the role's policies. ## Connect in Serval The dialog shows two read-only values: **Serval AWS Account ID** and **External ID** (your team's stable, Serval-generated value). These are for use in AWS - you don't edit them. The account ID to trust for your region is in [Get your credentials](#get-your-credentials). Enter your 12-digit AWS account ID. This becomes the connection's identifier in Serval. Enter a display label to tell accounts apart in Serval (for example, "Production"). It's a label only and doesn't affect the connection. Paste the Role ARN of the cross-account role you created. Submit is disabled until all three required fields are filled in and the Role ARN is well-formed. The dialog rejects a malformed Role ARN before you can submit (it must look like `arn:aws:iam::123456789012:role/`), but a well-formed ARN for a role that doesn't exist or doesn't trust Serval still connects and only fails when you run the "Test AWS Connection" health check, so verify the ARN before submitting. To connect additional AWS accounts, repeat the connect flow once per account - each account is a separate connection. ## Verifying the connection After connecting, run the health checks from the app instance page. **Test AWS Connection** - verifies Serval can assume your cross-account role by making a minimal IAM read call. * Success: "Successfully authenticated with AWS" * Role assumption fails (for example, a trust policy naming the wrong Serval account or lacking `sts:TagSession`, an External ID mismatch, or a nonexistent role): "Unable to authenticate with AWS. Please verify your cross-account role ARN and external ID are correct." * If role assumption works but the role can't read IAM: "Connection successful, but IAM role lacks iam:ListRoles permission." * If role assumption works but the IAM request fails for another reason: "Authenticated with AWS, but the IAM ListRoles request failed." **List AWS Organization Accounts** - verifies the role can list accounts in your AWS Organization. * Success: "Successfully retrieved \[number] accounts from AWS Organizations" * Role assumption fails: "Unable to authenticate with AWS. Please verify your cross-account role ARN and external ID are correct." * Standalone account (not in an Organization): "This AWS account is not part of an AWS Organization." * Permission missing but auth working: "Connection successful, but IAM role lacks organizations:ListAccounts permission." * Any other failure, such as throttling or a network problem (ignore the permission advice and read the error shown beneath the message): "Unable to access AWS Organizations. Ensure the IAM role has organizations:ListAccounts permission." "Test AWS Connection" is the authoritative connectivity signal. If it passes but "List AWS Organization Accounts" fails with "This AWS account is not part of an AWS Organization.", your connection is healthy - that result is expected for standalone accounts. ## Gotchas and troubleshooting Standalone AWS accounts that aren't part of an AWS Organization will always fail the "List AWS Organization Accounts" check with "This AWS account is not part of an AWS Organization." This does not mean the connection is broken - "Test AWS Connection" is the check that matters for connectivity. The IAM role sync filters to roles carrying a tag with the key "serval" - an account full of roles syncs zero resources until they're tagged. If a connected account's role list looks empty in Serval, check tags before debugging the connection. The dialog and Serval both reject a malformed Role ARN (anything that isn't `arn:aws:iam::<12-digit account ID>:role/`) before the connection is saved. A well-formed ARN for a role that doesn't exist or doesn't trust Serval still connects "successfully" and fails later at "Test AWS Connection" with "Unable to authenticate with AWS. Please verify your cross-account role ARN and external ID are correct." No region is stored on the connection - every workflow API action takes an explicit region. IAM is global so any region works for it, but a region must still be provided. Health checks default to us-east-1. The External ID is derived from your Serval team ID, so the same team always sees the same value - it survives reconnects. This is intentional so the ID can live in Terraform-managed trust policies without breaking. Each AWS account is its own app instance keyed by the 12-digit account ID. Multi-account organizations repeat the connect flow for each account; workflows can then target a specific account or iterate over all connected accounts. Every role assumption requests a 15-minute session with a unique session name, and credentials refresh automatically on expiry - long-running workflows reassume the role transparently. Each assumption appears as a separate session in CloudTrail, so don't be alarmed by many short sessions. Unlike most integrations, AWS requests aren't routed through Serval's host-allow-listed HTTP proxy: AWS request signing must happen client-side, so the workflow worker uses short-lived credentials to call AWS service endpoints (`*.amazonaws.com`) directly. The effective outbound surface is the endpoints of every service listed in the capability table under "What the AWS integration enables," plus AWS STS for the credential exchange Serval performs on your connection's behalf. Each Serval region runs in its own AWS account, and the trust policy must name the one that assumes your role: `992382851720` for United States organizations (`app.serval.com`), `311208284913` for European Union organizations (`app.eu1.serval.com`), and the account your own worker runs in for self-hosted deployments. The Connect AWS dialog shows the account for the region you're signed in to, and the trust policy must name that same account. If the dialog shows `992382851720` on a European Union tenant, that build predates the region-aware dialog, so use the table in [Get your credentials](#get-your-credentials) instead. Serval can't assume a role that trusts a different account, and "Test AWS Connection" fails with "Unable to authenticate with AWS. Please verify your cross-account role ARN and external ID are correct." If you're self-hosted, ignore the value in the dialog and confirm the worker's account ID with your Serval contact before writing the trust policy. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your AWS integration. # AWS Role Ingestion Source: https://docs.serval.com/sections/integrations/aws-role-ingestion How Serval discovers tagged IAM roles in your connected AWS accounts and grants users time-bound AWS sessions for them. ## About AWS Role Ingestion AWS Role Ingestion is the part of Serval's AWS integration that discovers IAM roles in your connected AWS accounts and makes them requestable in Serval. Serval ingests every role carrying a tag with key `serval`, together with its policy documents and maximum session duration, and lets approved users start short-lived, just-in-time (JIT) AWS sessions for those roles. This page covers the role sync, the AWS-side setup, and the bridge service that mints JIT sessions. For connecting the AWS account itself, see the [AWS integration](/sections/integrations/aws) page; for access-policy configuration, see [AWS Role Access](/sections/access-management/configuration/aws-role-access). **Authentication:** Cross-account IAM role (STS AssumeRole with an External ID) for role ingestion. JIT sessions use OIDC federation (STS AssumeRoleWithWebIdentity) against your Okta identity provider - brokered by Serval's cloud endpoints on Serval cloud, or by the self-hosted bridge service that runs alongside your worker on self-hosted deployments. **Data sync:** Scheduled full sync every 4 hours (with a 30-minute offset). There is no delta sync, so changes in AWS can take up to 4 hours to appear in Serval. ## What the AWS Role Ingestion integration enables | Capability | Description | | - | - | | IAM role ingestion | The built-in workflow "Fetch AWS IAM Roles for Resource Sync" ingests every IAM role tagged with key `serval` from each connected account, including inline policy documents, attached managed policy documents, and the role's maximum session duration. | | Assume Role entitlement | Each ingested role surfaces exactly one requestable entitlement named "Assume Role" ("Ability to assume this AWS IAM role") in Serval's access-request flow. | | Temporary (JIT) AWS sessions | Approved users mint short-lived AWS credentials (Access Key ID, Secret Access Key, Session Token) for a role using their OIDC identity (Okta in the standard setup). Session length is the shorter of the remaining approved access time and the role's maximum session duration, defaulting to 1 hour, with an AWS-enforced 15-minute minimum. | | Deferred deprovision timer | The granted access window starts counting down when the user opens their first AWS session, not when the request is approved. | | CloudTrail-attributable sessions | JIT sessions minted through the self-hosted bridge use the requester's email (truncated to 64 characters) as the session name, so activity in CloudTrail is attributable per user. Sessions minted through Serval cloud appear under the shared session name `serval-user-access`. | | Pre-built install workflows | The AWS integration ships two installable workflows: "Create AWS IAM Role" (installer approval by default) and "List AWS Organization Accounts" (no approval by default). | ## Get your credentials Set up an ingestion role in each AWS account Serval should read roles from. If you want users to mint AWS sessions, also complete the JIT setup. AWS documents the cross-account pattern in [Delegate access across AWS accounts using IAM roles](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user.html) and the External ID pattern in [How to use an external ID for third-party access](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html). In the AWS console, go to **IAM > Roles > Create role** and choose **AWS account** as the trusted entity type. Enter the AWS account ID that performs the role assumption for your region: `992382851720` for United States organizations (`app.serval.com`), `311208284913` for European Union organizations (`app.eu1.serval.com`), or the account your own worker runs in if self-hosted. Ask [support@serval.com](mailto:support@serval.com) if you're unsure which region you're on. Tick **Require external ID** and paste the External ID shown in Serval's Connect AWS dialog. Skip the permission-policies step for now (you will add an inline policy next), then name and create the role. Open the role, go to **Trust relationships > Edit trust policy**, and add a second statement allowing the action `sts:TagSession` for the same account principal. The trust policy AWS generates by default only allows `sts:AssumeRole` with the External ID condition. Without the separate `sts:TagSession` statement, Serval's role assumption fails. Pick the tab for your region and replace `` with the External ID from Serval's Connect AWS dialog: ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::992382851720:root" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "" } } }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::992382851720:root" }, "Action": "sts:TagSession" } ] } ``` ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::311208284913:root" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "" } } }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::311208284913:root" }, "Action": "sts:TagSession" } ] } ``` Replace `` with the AWS account your Serval worker runs in. ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam:::root" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "" } } }, { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam:::root" }, "Action": "sts:TagSession" } ] } ``` Under **Permissions > Create inline policy**, allow these seven actions on Resource `*`: `iam:ListRoles`, `iam:GetRole`, `iam:ListRolePolicies`, `iam:GetRolePolicy`, `iam:ListAttachedRolePolicies`, `iam:GetPolicy`, `iam:GetPolicyVersion`. ```json theme={null} { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "iam:ListRoles", "iam:GetRole", "iam:ListRolePolicies", "iam:GetRolePolicy", "iam:ListAttachedRolePolicies", "iam:GetPolicy", "iam:GetPolicyVersion" ], "Resource": "*" } ] } ``` Add a tag with key `serval` (the value may be empty) to every role Serval should ingest and grant. Untagged roles are ignored entirely. Self-hosted workers perform the cross-account role assumption themselves, so the worker pod needs AWS credentials. The standard setup uses [EKS Pod Identity](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html) (see the [agent setup guide](https://docs.aws.amazon.com/eks/latest/userguide/pod-id-agent-setup.html)): create a Kubernetes service account for the worker (the standard setup names it `serval-worker-sa` - the worker chart does not create one for you), reference it from the worker deployment, and add an EKS Pod Identity association binding it to an IAM role that allows `sts:AssumeRole` and `sts:TagSession` on Resource `*`. This is required for ingestion itself, even if you never set up JIT sessions. Example Terraform for the worker IAM role, its assume-role/permission policies, and the Pod Identity association: ```hcl theme={null} # The IAM Role to give to the Serval worker resource "aws_iam_role" "this_service_role" { name = "eks-pod-identity-serval-worker" assume_role_policy = data.aws_iam_policy_document.assume_role.json } # Trust policy which allows the EKS pod identity system to use this role data "aws_iam_policy_document" "assume_role" { statement { effect = "Allow" principals { type = "Service" identifiers = ["pods.eks.amazonaws.com"] } actions = [ "sts:AssumeRole", "sts:TagSession" ] } } # Policy document and attachment so the role can assume roles in other accounts data "aws_iam_policy_document" "policy" { statement { effect = "Allow" actions = [ "sts:AssumeRole", "sts:TagSession" ] resources = ["*"] } } resource "aws_iam_policy" "policy" { name = "assume-role-policy-serval-worker" description = "Policy to allow assuming roles in other AWS accounts." policy = data.aws_iam_policy_document.policy.json } resource "aws_iam_role_policy_attachment" "policy_attachment" { role = aws_iam_role.this_service_role.name policy_arn = aws_iam_policy.policy.arn } # Association between the role and the "serval-worker-sa" service account resource "aws_eks_pod_identity_association" "pod_identity_association" { cluster_name = "" namespace = "" service_account = "serval-worker-sa" role_arn = aws_iam_role.this_service_role.arn } ``` The matching service account in the worker's Kubernetes namespace: ```yaml theme={null} --- apiVersion: v1 kind: ServiceAccount metadata: name: serval-worker-sa ``` The bridge is a small service that runs alongside your self-hosted worker. Its Kubernetes Service is named `serval-bridge` (port 80, forwarding to 8080) and it must be reachable by your users over your VPN. It exchanges each user's Okta identity for temporary AWS credentials. On Serval cloud (no self-hosted worker), JIT sessions are brokered by Serval's hosted endpoints instead - no bridge deployment is needed, and sessions appear in CloudTrail under the name `serval-user-access`. The AWS-side identity provider and trust-policy steps below still apply; ask your Serval contact for the OIDC values to use. In Okta Admin, go to **Applications > Create App Integration** and create an OIDC web application following [Okta's web-app sign-in guide](https://developer.okta.com/docs/guides/sign-into-web-app-redirect/go/main/). Set the sign-in redirect URI to `/oidc/auth/callback` on your bridge host, and note the Client ID and Client Secret. The bridge requests the `openid`, `profile`, and `email` scopes at login, and the token's email claim must match the user's Serval login email. Only `/oidc/auth/login` and `/oidc/auth/callback` exist on the bridge. Leave any Okta sign-out redirect unused - there is no logout route. Provide the Client ID and Client Secret to your Serval contact for the bridge deployment. They are supplied to the bridge through the `bridge-secrets` Kubernetes secret, which only the bridge deployment references. In each AWS account, go to **IAM > Identity providers > Add provider**. Set the provider URL to your Okta instance URL and the audience to the OIDC app's Client ID. On each role users should be able to assume, add a trust-policy statement with the Federated principal `arn:aws:iam:::oidc-provider/`, the action `sts:AssumeRoleWithWebIdentity` (see the [AWS API reference](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html)), and a StringEquals condition that `:aud` equals ``. The placeholders: `` is the AWS account the role lives in, `` is your Okta instance URL as registered on the identity provider, and `` is the Okta OIDC app's Client ID. ## Connect in Serval Role ingestion uses the standard AWS connection - follow the connect flow on the [AWS integration](/sections/integrations/aws) page to open the Connect AWS dialog, then fill it in as follows. The dialog displays two read-only badges: **Serval AWS Account ID** and **External ID**. Use both in your ingestion role's trust policy. The account ID is the Serval account for your region and matches the [region table on the AWS page](/sections/integrations/aws#get-your-credentials). If the badge shows `992382851720` on a European Union tenant, that build predates the region-aware dialog, so use the table instead. Self-hosted deployments trust the account their own worker runs in instead. The External ID is a deterministic 64-character value derived from your team, so it is identical on every reconnect and safe to hardcode in Terraform trust policies. Enter the 12-digit ID of the account you are connecting. There is no format validation; this value becomes the connection's service instance ID. A display label for the account - this is what the connection is called in Serval. The ARN of the ingestion role you created. The dialog rejects a malformed Role ARN before you can submit, but a well-formed ARN for a role that doesn't exist or doesn't trust Serval still connects and only surfaces when the "Test AWS Connection" health check or the next scheduled sync fails. Submit stays disabled until all three required fields are filled in and the Role ARN is well-formed. ## Verifying the connection Run the connection health checks after connecting. **Test AWS Connection** - confirms Serval can assume your cross-account role and read IAM. This is the authoritative check before debugging role ingestion. * Success: "Successfully authenticated with AWS" * Failure (role assumption fails: for example, a trust policy naming the wrong Serval account or lacking `sts:TagSession`, an External ID mismatch, or a nonexistent role): "Unable to authenticate with AWS. Please verify your cross-account role ARN and external ID are correct." * Failure (role assumed, but the inline policy is missing the IAM read permission the sync also needs): "Connection successful, but IAM role lacks iam:ListRoles permission." * Failure (role assumed, but the IAM request failed for another reason): "Authenticated with AWS, but the IAM ListRoles request failed." **List AWS Organization Accounts** - confirms Organizations API permissions for the optional account-listing workflow. * Success: "Successfully retrieved \[number] accounts from AWS Organizations" * Failure (role assumption fails): "Unable to authenticate with AWS. Please verify your cross-account role ARN and external ID are correct." * Failure (standalone account): "This AWS account is not part of an AWS Organization." This is expected for accounts outside an AWS Organization and is not a connectivity problem. * Failure (permission only): "Connection successful, but IAM role lacks organizations:ListAccounts permission." * Failure (any other error, such as throttling or a network problem: ignore the permission advice and read the error shown beneath the message): "Unable to access AWS Organizations. Ensure the IAM role has organizations:ListAccounts permission." A green "Test AWS Connection" with zero roles appearing in Serval almost always means tagging, not connectivity: only roles tagged with key `serval` are ingested, and a newly tagged role can take up to 4 hours to show up on the next scheduled sync. ## Gotchas and troubleshooting The sync filters on tag key `serval` exactly; the value is ignored and may be empty. An account full of roles syncs zero resources until tagging is done, and untagging a role removes it on the next full sync. Check tags before debugging the connection. Role ingestion is a full sync every 4 hours (30-minute offset) with no delta sync. The same lag applies to session-length changes: JIT session caps are read from Serval's ingested copy of the role, so raising a role's maximum session duration in AWS only takes effect after the next sync. The ingestion role's trust policy needs a second statement allowing `sts:TagSession` for the trusted account principal alongside the `sts:AssumeRole` statement with its External ID condition. Workers running under EKS Pod Identity carry transitive session tags, so role assumption fails against a trust policy without TagSession. Older guidance mentioned a 3-hour cap; that is stale. The session lasts the shorter of the remaining approved access time and the role's ingested maximum session duration. If that duration is missing, the default is 1 hour, and AWS enforces a 15-minute minimum (shorter requests are rounded up). On a failed attempt, the session broker retries once with the 1-hour default. Deprovisioning is deferred until after first access: a user's granted duration begins when they start their first AWS session, not when the request is approved. Policy-fetch errors are logged but do not fail the sync - the role is still ingested with whichever policy lists succeeded, possibly none. A role with no policies in Serval may indicate missing `iam:GetRolePolicy`, `iam:GetPolicy`, or `iam:GetPolicyVersion` permissions rather than a truly policy-less role. `iam:ListRoleTags`, `rds:DescribeDBInstances`, `rds:DescribeDBClusters`, `ec2:DescribeInstances`, `eks:DescribeCluster`, and `eks:ListClusters` appeared in earlier versions of the inline policy, but no shipped ingestion workflow uses them (tags come back on `iam:GetRole`). Only the seven actions listed above are required for role ingestion. The optional install workflows have their own needs - `organizations:ListAccounts` for "List AWS Organization Accounts", and `iam:CreateRole` plus `iam:PutRolePolicy` for "Create AWS IAM Role" - and your own custom workflows may need more. Ingestion assumes the role with a fresh UUID session name and a 15-minute duration on every credential refresh, so frequent short UUID-named sessions are expected. JIT sessions minted through the self-hosted bridge are named with the requester's email truncated to 64 characters, giving per-user attribution; sessions minted through Serval cloud appear under the shared name `serval-user-access`. The Kubernetes Service is `serval-bridge` (port 80, forwarding to 8080); `svbridge-api` is the container name inside the deployment. The bridge must be reachable by users over your VPN, and its OIDC secrets live in the `bridge-secrets` Kubernetes secret. The bridge serves `/oidc/auth/login` and `/oidc/auth/callback` only. Configure the Okta sign-in redirect to `/oidc/auth/callback` and treat any sign-out redirect URI as unused. During the OIDC exchange, the email claim in the Okta token is compared to the user's Serval login email. A mismatch fails with "Account mismatch - You tried to log in with email \[Okta email] but your Serval account uses \[Serval email]. Please ensure you are using the same login email for your Serval account and your auth provider." Users with different aliases in Okta and Serval cannot start sessions until the emails are aligned. The connect dialog rejects a malformed Role ARN, but a well-formed ARN that names the wrong role shows up later as a failed "Test AWS Connection" health check or a failed scheduled sync - not at session start. Separately, the self-hosted bridge validates the ARN of the role being granted and rejects any value that does not start with `arn:` with the error "invalid role ARN format"; since that ARN is ingested from AWS itself, hitting this error usually indicates corrupted or stale ingested data rather than a setup typo. On self-hosted deployments the browser talks to the bridge directly, so "Unable to connect to the bridge service" errors usually mean the user is not on the VPN, or third-party cookies are blocked when the bridge sits behind a service like Cloudflare Zero Trust. See [Resolving Cookie Issues for AWS Session Granting](/sections/self-hosting/deployment/onprem/ResolvingCookieIssuesforAWSSessionGranting) for browser-specific fixes. AWS request signing happens inside the worker, so the worker calls AWS endpoints (`*.amazonaws.com`) directly with short-lived 15-minute credentials instead of routing through Serval's host-allow-listed proxy. If you restrict the worker's egress, allow `iam.amazonaws.com`, `organizations.us-east-1.amazonaws.com`, and `sts.us-west-1.amazonaws.com` (the self-hosted bridge likewise calls `sts.us-west-1.amazonaws.com`). Custom workflows that use other AWS submodules (EC2, S3, Lambda, RDS) call those services' regional endpoints too. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your AWS Role Ingestion integration. # Azure Resource Manager Source: https://docs.serval.com/sections/integrations/azure-resource-manager Connect Microsoft Azure's management control plane to Serval so workflows can manage subscriptions, resources, and Azure RBAC role assignments on demand. ## About Azure Resource Manager Azure Resource Manager (ARM) is the deployment and management control plane for Microsoft Azure - subscriptions, resource groups, role assignments, virtual machines, and every other resource provider are managed through it. The Serval integration lets workflows reach any part of the ARM API through Serval's authenticated proxy, and it ships two ready-to-install workflows for assigning and unassigning Azure RBAC roles. Two built-in health checks confirm that authentication works and that the connection can see your subscriptions. **Authentication:** Sign in with Microsoft (recommended where available) or Client Credentials with your own Microsoft Entra app registration. **Data sync:** On-demand only. Nothing is synced into Serval on a schedule - workflows call Azure at run time, and Serval mints or refreshes tokens automatically for each request. ## What the Azure Resource Manager integration enables | Capability | Description | | - | - | | ARM API requests from workflows | Workflows can make any read or write call to Azure Resource Manager, covering subscriptions, resource groups, role assignments, virtual machines, and any other resource provider. | | Assign Azure RBAC Role (installable workflow) | Assigns an Azure RBAC role to a user, group, service principal, or foreign group at a chosen scope. Built-in roles Owner, Contributor, Reader, and User Access Administrator are resolvable by name; custom roles are accepted as role definition IDs. If the principal already holds the role, the workflow reports success with no action taken. Requires installer approval by default. | | Unassign Azure RBAC Role (installable workflow) | Finds the role assignment matching the principal and role at the given scope and removes it. Errors if the principal does not hold that role at that scope. Requires installer approval by default. | | Health checks | Two built-in checks, "Test Azure Resource Manager Connection" and "List Azure Subscriptions", verify that the integration can authenticate and can see your subscriptions. | Anything defined in the [Azure Resource Manager API](https://learn.microsoft.com/en-us/rest/api/resources/) can be accessed through Serval. ## Get your credentials There are two ways to connect. Sign in with Microsoft needs no setup on your side beyond an Azure account with subscription access. Client Credentials requires a Microsoft Entra app registration that you create and authorize yourself. No credentials to create. You sign in with your own Microsoft account and Serval uses its operator-managed Microsoft Entra app (the same app as the Microsoft Graph integration) to act on your behalf. The account you sign in with must have access to at least one Azure subscription (Reader or higher). If it can see zero subscriptions, the connection fails. You will create an app registration with a client secret, grant it the Azure Service Management API permission, and give its service principal Azure RBAC roles on every subscription Serval should manage. Microsoft's official guide is [Register an application with Microsoft Entra](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app). Sign in to the [Azure Portal](https://portal.azure.com) with admin privileges, open the [Microsoft Entra admin center](https://entra.microsoft.com), and go to **App registrations**. Click **New registration**. Name it (for example, "Serval Azure Resource Manager Integration"), set **Supported account types** to **Accounts in this organizational directory only**, leave **Redirect URI** blank, and click **Register**. From the app's **Overview** page, copy the **Application (client) ID** (your Client ID) and the **Directory (tenant) ID** (your Tenant ID). Go to **Certificates & secrets**, then **Client secrets**, then **New client secret**. Add a description, choose an expiration, click **Add**, and copy the secret **Value** immediately. This is your Client Secret. Copy the **Value** column, not the Secret ID - Azure shows the Value only once. If you miss it, create a new secret. Go to **API permissions**, then **Add a permission**, choose **Azure Service Management** (not Microsoft Graph), select **user\_impersonation**, and click **Add permissions**. Then click **Grant admin consent** for your organization and verify the status shows **Granted**. In each subscription Serval should manage, open **Access control (IAM)**, then **Add**, then **Add role assignment**. Pick a role (Reader for read-only, Contributor to manage resources, Owner sparingly), select **User, group, or service principal**, search for your app registration by name, select it, and click **Review + assign**. Repeat for every subscription. The API permission alone grants nothing in Azure. Without RBAC role assignments on each subscription, the connection authenticates but cannot see or manage anything. For general Entra app registration concepts such as admin consent and secret rotation, see the [Microsoft 365 (Microsoft Graph)](/sections/integrations/microsoft-graph) integration page. ## Connect in Serval Open the Azure Resource Manager integration in Serval and click **Connect**. This option appears (labeled **Recommended**) only when your Serval instance has Microsoft OAuth configured. If you do not see it, use Client Credentials instead. Sign in and approve the requested access. Microsoft always shows the consent screen, including when you reauthorize. Serval lists the subscriptions your account can see, takes the tenant from the first one, and names the connection "Azure (\[first subscription name])". If your account can see zero subscriptions, the connection fails with "no subscriptions found - user may not have access to any Azure subscriptions". Open the Azure Resource Manager integration in Serval, click **Connect**, and choose **Client Credentials**. Every field is required (labels show an asterisk), and the submit button stays disabled until all four are filled. Values are trimmed of surrounding whitespace. * **Instance Name** - "A friendly name to identify this integration", for example "Production Azure". * **Tenant ID** - "Azure AD Directory (Tenant) ID from the Azure Portal". * **Client ID** - "Application (Client) ID from your Azure AD App Registration". * **Client Secret** - "Client Secret value from your Azure AD App Registration". Entered as a masked password field; paste the secret **Value**, not the Secret ID. There is no format checking at submit time - a wrong value surfaces at the first token fetch or health check. Common messages include "Please verify your Client ID and Tenant ID in the Azure Portal." and "Client authentication failed for application '\[client ID]'. Please verify the Client ID and Client Secret are correct." **Rotating or updating credentials:** clicking **Reconnect** on a connected integration reopens this same dialog with empty fields - nothing is prefilled. All four fields are required again, so have the full set of values on hand (including the Client Secret) even if you are only changing one of them. ## Verifying the connection The integration includes two health checks. **Test Azure Resource Manager Connection** verifies that the integration can authenticate by listing your Azure subscriptions. * Success: "Successfully connected to Azure Resource Manager. Found \[number] subscription(s)." * Authentication failure: "Authentication failed. Please verify your Azure credentials are correct and have not expired." * Authorization failure: "Authorization failed. The Azure application may lack permissions to list subscriptions." * Any other error: "Unable to connect to Azure Resource Manager. Please verify your integration configuration." **List Azure Subscriptions** lists every subscription visible to the integration and reports how many are enabled. * Success: "Found \[number] subscription(s), \[number] enabled." * No subscriptions visible: "No subscriptions found. The integration may lack permissions or there are no subscriptions in this tenant." * Request errors: "Failed to list Azure subscriptions. Please check your permissions." If authentication succeeds but **List Azure Subscriptions** reports "No subscriptions found. The integration may lack permissions or there are no subscriptions in this tenant.", your credentials are valid but the app's service principal has no Azure RBAC roles. Add Reader or higher on each subscription via **Access control (IAM)** and re-run the check. ## Gotchas and troubleshooting Registering the Entra app and granting the Azure Service Management API permission is not enough: what the connection can actually do in Azure is governed by RBAC role assignments on each subscription. Without them, both health checks fail - "No subscriptions found. The integration may lack permissions or there are no subscriptions in this tenant." is the telltale result. Assign Reader, Contributor, or Owner to the app's service principal per subscription via **Access control (IAM)**, and repeat for every subscription Serval should reach. Entra client secrets have a fixed expiration. Once expired, requests fail with "The client secret for application '\[client ID]' has expired." and the connection health check reports authentication failure. When creating a secret, copy the **Value** column (not the Secret ID) immediately - Azure never shows it again. When it expires, generate a new secret under **Certificates & secrets**, then click **Reconnect** in Serval and enter the new secret Value along with the other connection fields. The OAuth connect path detects your tenant by listing subscriptions: the tenant comes from the first subscription returned, and the connection is auto-named "Azure (\[first subscription name])". If the signed-in user can see zero subscriptions, the install fails with "no subscriptions found - user may not have access to any Azure subscriptions". Sign in with an account that has at least Reader on a subscription. The connect dialog shows the **Sign in with Microsoft** button (labeled **Recommended**) only if your Serval instance has Microsoft OAuth credentials configured. Otherwise, Client Credentials is the recommended path. Reauthorizing always brings up the Microsoft consent screen again. There is no partial-edit form for this integration. Clicking **Reconnect** on a connected integration reopens the connect dialog with every field empty, and the submit button stays disabled until Instance Name, Tenant ID, Client ID, and Client Secret are all filled in. Keep the full set of values handy when rotating a client secret - you will re-enter the other three values along with the new secret Value. The integration's outbound allow-list covers only management.azure.com. Other Microsoft endpoints - Microsoft Graph, Key Vault or Storage data planes, and so on - are not reachable through this integration. Use the [Microsoft 365 (Microsoft Graph)](/sections/integrations/microsoft-graph) integration for Graph calls. Both bundled RBAC workflows require the scope to contain a subscription segment (used to resolve role definition IDs). Management-group-only scopes are rejected with "Invalid scope: \[scope]. Must include /subscriptions/\[subscription ID]". Note that Assign Azure RBAC Role is idempotent: if the principal already holds the role, it reports success with no action taken. For deeper reference, see the [Azure Resource Manager documentation](https://learn.microsoft.com/en-us/azure/azure-resource-manager/) and the [Azure RBAC documentation](https://learn.microsoft.com/en-us/azure/role-based-access-control/). *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Azure Resource Manager integration. # BambooHR Source: https://docs.serval.com/sections/integrations/bamboohr BambooHR is an HR information system for employee records, time off, time tracking, and hiring - Serval connects to it with an API key so your workflows can read and update your HR data on demand. ## About BambooHR BambooHR is a human resources information system (HRIS) for employee records, time off, time tracking, hiring, and HR reporting. Each Serval connection targets a single BambooHR company instance, identified by its API domain (for example, mycompany.bamboohr.com), using an API key you generate inside BambooHR. The connection acts as the BambooHR user who generated the key, so everything Serval can see or change is limited by that user's BambooHR permissions. **Authentication:** API key, generated by a BambooHR user. There is no OAuth app to register - you paste the key and your API domain into Serval. **Data sync:** On-demand only. There is no background or scheduled sync and Serval registers no BambooHR webhooks; data is read or changed only when a workflow runs. ## What the BambooHR integration enables | Capability | Description | | - | - | | Employee records | Read the full employee directory, look up or update individual employees, and work with job and compensation history, photos, dependents, and employee files. | | Time off | Work with time-off policies and types, balances and balance adjustments, requests and approvals, history, and who's out. | | Time tracking and scheduling | Clock in/out, hour and timesheet entries, projects and tasks, break policies, schedules, and shifts. | | Hiring and onboarding | Applicant tracking (applications, jobs, statuses, comments, hiring leads), new-hire packets, and onboarding experiences. | | Performance, compensation, benefits, and training | Employee goals, compensation planning cycles, pay grades and bands, total rewards, benefits, and training records. | | Reports, datasets, and metadata | Run custom reports, query datasets, and read account metadata such as fields, tables, lists, users, and company info. | | Full API access | Workflows reach BambooHR through one generic action that covers the entire BambooHR REST API, so anything not listed above is still reachable. | Anything defined in the [BambooHR API](https://documentation.bamboohr.com/reference/getting-started) can be accessed through Serval. ## Installable workflows Each workflow identifies the requesting employee automatically, so people can act on their own data without looking up IDs. | Bundle | Workflows | | - | - | | **Directory** | **Get My BambooHR Profile** and **Find a BambooHR Coworker** - look up your own profile or a coworker's role, department, and manager. | | **Time Off** | **Get My BambooHR Time Off Balance**, **List Who's Out in BambooHR**, and **Request Time Off in BambooHR**. | | **Personal Info** | **Update My BambooHR Contact Info** - update your own home address and phone numbers. | Read-only workflows run without approval by default. Workflows that write back to BambooHR - **Request Time Off in BambooHR** and **Update My BambooHR Contact Info** - require approval by the installer by default. All writes are still bounded by the API key owner's BambooHR permissions. ## Get your credentials You need a BambooHR API key. Keys are generated per user and inherit exactly that user's BambooHR permission level, so generate the key from an account whose access matches what your workflows need. BambooHR's own guide is here: [BambooHR API getting started](https://documentation.bamboohr.com/docs/getting-started). Sign in to your BambooHR account. Click your name in the lower-left corner of any page. Choose **API Keys** from the menu. If you do not see it, your account lacks permission to create keys - contact your BambooHR administrator. Click **Add New Key** and give it a descriptive name, such as "Serval Integration". Click **Generate Key**, then copy the key and store it securely. Anyone with this key can act as your BambooHR user. Treat it like a password and store it somewhere safe - you will paste it into Serval in the next section. Workflows will only ever see and change what the key's owner can see and change in BambooHR. If your workflows need broad employee data, generate the key from an account with the appropriate permission level. ## Connect in Serval Start connecting BambooHR from Serval's integrations page. Enter your full BambooHR domain, for example mycompany.bamboohr.com. Use the bare domain only - no "https\://", no path, and no trailing slash. Invalid values are rejected with the error "Must be a valid BambooHR domain (e.g., mycompany.bamboohr.com)". Paste the key you generated in BambooHR. The field's helper text reads: "Your BambooHR API key. Generate one by clicking your name in the lower left corner > API Keys". Save the form to create the connection. Serval verifies it with a health check (see below). If you edit this connection later - for example, to rotate your BambooHR API key - always re-enter the complete key in the **API Key** field before saving. ## Verifying the connection Serval verifies the connection with a single lightweight, read-only call to BambooHR (it reads your account's field metadata) using your saved API Domain and key. If that call succeeds, the connection is healthy. If it fails, the connection is marked unhealthy - a failure points to an authentication or domain problem (a bad or revoked API key, or a wrong API Domain) rather than a data issue. A healthy connection only proves the key and domain work. If a workflow gets permission errors or cannot see certain fields even though the connection is green, check the BambooHR permission level of the user who generated the key - that user's access is the ceiling for everything Serval can do. ## Gotchas and troubleshooting BambooHR treats every request as if the user who generated the key were using the product. Field visibility and write access follow that user's BambooHR permission level, so missing fields or "permission denied" failures often mean the key's owner lacks access - not that the integration is broken. Fix it by adjusting that user's permissions in BambooHR or generating a key from a more privileged account. The connect form only accepts a value shaped like mycompany.bamboohr.com - one subdomain followed by .bamboohr.com. Values with "https\://", a path, a trailing slash, or a non-bamboohr.com host are rejected with the error "Must be a valid BambooHR domain (e.g., mycompany.bamboohr.com)". BambooHR fields can be customized per company, so a field present in one organization's data may be absent in another's - and BambooHR only returns fields the key's user is allowed to see. Also note the employee directory returns all employees in one response, with no pagination. Serval attaches your API key only to requests going to subdomains of bamboohr.com, and workflow calls are made against your configured API Domain. Requests to any other host are blocked from carrying the credential. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your BambooHR integration. # Beekeeper Source: https://docs.serval.com/sections/integrations/beekeeper Connect Serval to Beekeeper, the frontline-workforce communication platform, so workflows can manage tasks, shifts, forms, chats, and more in your tenant. ## About Beekeeper Beekeeper is a mobile-first communication and operations platform for frontline workforces, now part of LumApps. It gives non-desk employees a single app for company news streams, chat, tasks, shift schedules, forms, and documents. Serval connects to your Beekeeper tenant using a bot access token plus your tenant subdomain, and attaches the token securely to every request it sends to Beekeeper on your behalf. Once connected, Serval workflows can reach frontline employees where they already work - sending messages, assigning tasks, managing shifts and events, and reading back submissions and profile data. **Authentication:** API key (bot access token + subdomain). No OAuth flow, and the bot token does not expire. **Data sync:** On-demand only. There is no background sync or data ingestion - Serval calls your Beekeeper tenant's API at the moment a workflow runs. ## What the Beekeeper integration enables | Capability | Description | | - | - | | People, posts, and groups | Look up users and profiles, and work with posts, streams, comments, files, groups, conversations, and surveys. | | Tasks | Manage tasks, subtasks, approvals, task history, and exports. | | Shifts | Work with schedules, shifts, and shift imports (including bulk shift imports). | | Forms | Access forms, submissions, permissions, and surveys. | | Company events | Manage company events, audiences, and invitees. | | Chats | Work with group chats, chat members, and messages (Chats 2.0). | | Artifacts | Manage files, folders, and their access control lists. | | Beekeeper workflows | Read and manage Beekeeper's own workflow definitions, executions, and inventory. | | Webhook subscriptions | Manage your tenant's Beekeeper webhook subscriptions. | | Create Task (installable workflow) | Creates a new Beekeeper task in the To Do state, with a title, description, optional assignee, and optional due date. Requires installer approval by default. | | Send Direct Message (installable workflow) | Sends a chat message to a Beekeeper user; the message body supports rich text. Requires installer approval by default. | Anything defined in the [Beekeeper API](https://developers.beekeeper.io/docs/beekeeper-api/a5a2c5e292428-beekeeper-rest-api) can be accessed through Serval. ## Get your credentials Serval connects with a **bot account** created in your Beekeeper admin dashboard. You will need the bot's API access token and your tenant subdomain. Beekeeper's official guide is here: [Set up a bot account in the dashboard](https://developers.beekeeper.io/docs/articles/ZG9jOjMyNzYwMDc5-1-set-up-a-bot-account-in-the-dashboard). Go to your tenant's dashboard (your-subdomain.beekeeper.io) and click the **speedometer** icon on the right-hand side of the top navigation bar to open the admin dashboard. Admin access is required to manage bot accounts. In the left navigation, open the **Extensions** tab, then the **Bot Accounts** subtab. Create a bot account and give it a recognizable name, for example "Serval". The bot's name and avatar are what employees see when Serval posts or messages on its behalf. Copy the token from the Bot Accounts list (a UUID-like value such as `fae00bbc-b0f6-4ace-8e13-7d53b58076e1`) and keep it somewhere safe. You will paste it into Serval in the next section. Give the bot access to the surfaces you plan to use - for example, admin permission for posting, plus access to Tasks, Shifts, and Forms if you rely on those areas. This is the "company" part of company.beekeeper.io. You will enter it in Serval alongside the token. Serval uses it to build the base URL `https://company.beekeeper.io/api/2/` for every API call. Copy the token only - do not include any "Token " or "Bearer " prefix when you paste it into Serval. Serval adds the correct authorization scheme automatically. Beekeeper bot access tokens do not expire. To revoke Serval's access, delete or regenerate the token in the Beekeeper dashboard. If a Beekeeper developer link opens on api.lumapps.com, that is expected - Beekeeper's developer docs moved under LumApps after the acquisition, and the old links redirect there. ## Connect in Serval In Serval, add the **Beekeeper** integration to open the connect form. Both fields are required - leaving either blank shows "This field is required". Fill in **Subdomain** - "Your Beekeeper subdomain, e.g. 'company' for company.beekeeper.io". The field is forgiving: pasting company, company.beekeeper.io, or a full URL all resolve to the bare lowercase subdomain. The subdomain also becomes the connection's display name in Serval. Fill in **Access Token** - "Bot access token from your Beekeeper dashboard (Authorization: Token ...). The token does not expire." It is a password-style field, so the value is hidden as you type. Paste the raw token only. After saving, the token is shown masked - bullets with only the last 4 characters visible. Health checks run automatically right after the connection is created (see Verifying the connection below). When editing an existing Beekeeper connection, always re-enter **both** values before saving: keep the **Subdomain** filled in, and click **Replace** next to the **Access Token** and paste the full token. Do not clear a pre-filled field, and do not save while the Access Token still shows only its masked value - re-enter both values any time you update the connection, including token rotations. ## Verifying the connection Health checks run once automatically after you create the connection, and you can re-run them anytime from the Health Checks section on the connection's settings page. The status check calls Beekeeper's authenticated `GET /api/2/status` endpoint. | Health check | What it verifies | On success | On failure | | - | - | - | - | | Get Beekeeper Status | The subdomain and access token are valid and Beekeeper is reachable. | "Successfully reached the Beekeeper API." | "Unable to reach Beekeeper. Please verify the subdomain and access token are correct." | | List Beekeeper Schedules | The Shifts area is reachable with your token's permissions; reports how many schedules came back. | "Successfully listed schedules from Beekeeper (sample size: \[number])." | "Unable to list schedules from Beekeeper. Please verify the access token has Shifts permissions." | | List Beekeeper Forms | The Forms area is reachable with your token's permissions. | "Successfully listed forms from Beekeeper." | "Unable to list forms from Beekeeper. Please verify the access token has Forms permissions." | If "Get Beekeeper Status" passes but the Schedules or Forms checks fail, your token is valid - the bot account just lacks Shifts or Forms permissions in Beekeeper. Grant the bot those product permissions in the dashboard, or expect those two checks to fail if you do not use those areas. ## Gotchas and troubleshooting Any time you update this connection - rotating the token, fixing the subdomain, or anything else - re-enter both values before saving. Keep the Subdomain filled in, and click **Replace** next to the Access Token and paste the full token. Do not save while the Access Token still shows only its masked value, and do not clear a pre-filled field - the connection can stop working until both values are entered again. Beekeeper uses a "Token" authorization scheme rather than the more common "Bearer" (see [Beekeeper's authentication guide](https://developers.beekeeper.io/docs/articles/0e819f41aa404-authentication)). Serval handles this automatically, so paste only the raw token value into the Access Token field. Including a "Token " or "Bearer " prefix will break authentication. These two checks exercise product-specific permissions. A failing Schedules or Forms check with a passing status check means the bot account needs Shifts or Forms access granted in the Beekeeper dashboard - the token itself is fine. You can paste company, company.beekeeper.io, or a full URL with a trailing slash - Serval normalizes them all to the bare lowercase subdomain (everything before the first dot, with any protocol and trailing slash stripped). That normalized subdomain also becomes the connection's display name in Serval. There is no reconnect cadence to plan for. However, if you rotate or delete the bot account in Beekeeper, the connection breaks until you update it in Serval - and when you do, keep the Subdomain filled in and use Replace to paste the new token in full. Following the LumApps acquisition, developers.beekeeper.io links - including the developer portal itself - redirect to api.lumapps.com. The links in this page were verified to resolve - if a provider link looks unfamiliar, that redirect is why. ## Additional resources For admin guides, including bot account management, see the [Beekeeper Help Center](https://help.beekeeper.io/). The full REST API reference is available in the [Beekeeper API documentation](https://developers.beekeeper.io/docs/beekeeper-api/a5a2c5e292428-beekeeper-rest-api). *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Beekeeper integration. # BeyondTrust Password Safe Source: https://docs.serval.com/sections/integrations/beyondtrust-password-safe Connect BeyondTrust Password Safe to manage privileged access requests, group membership, and password rotation. Connect **BeyondTrust Password Safe** to automate privileged account access and password management. This integration uses the BeyondInsight and Password Safe public API and is available in beta. For remote-access users, asset groups, and the PRA vault, connect [BeyondTrust Privileged Remote Access](/sections/integrations/beyondtrust-pra) separately. ## Before you connect You need an instance reachable over HTTPS and an OAuth application user in BeyondInsight: 1. Create an API registration of type **API Access Policy**. 2. Add the required IP authentication rule for the source addresses that connect to BeyondTrust. Contact **[support@serval.com](mailto:support@serval.com)** for Serval's egress addresses before connecting. For a self-hosted deployment or a self-hosted worker using direct routing, allowlist its outbound source addresses instead. 3. Create an application user, assign the API access policy, and record its client ID and client secret. 4. Add the application user to a group with the permissions your workflows need. 5. Enable API access on the managed accounts you want to use. The connection uses the application user's identity. It doesn't impersonate the person requesting help in Serval. BeyondTrust continues to enforce its access policies, approval requirements, and account permissions. See BeyondTrust's [API registration guide](https://docs.beyondtrust.com/bips/docs/ps-configure-api-registration), [SignAppIn reference](https://docs.beyondtrust.com/bips/reference/post-api-public-v3-auth-signappin), and [API authentication overview](https://docs.beyondtrust.com/bips/reference/beyondinsight-and-password-safe-api-usage) for setup and authentication details. API-key authentication, interactive multifactor challenges, and client-certificate authentication aren't supported by this connection. ## Connect to Serval In **Integrations > All integrations**, select **BeyondTrust Password Safe**. * **Instance Host**: Your instance hostname, such as `passwordsafe.example.com`. An optional port is supported. Don't include a path or an HTTP URL. * **Client ID**: The application user's OAuth client ID. * **Client Secret**: The application user's OAuth client secret. Serval stores the credentials and manages authentication sessions for you. Run **Test Connection**. It authenticates and reads managed account metadata. A successful connection can return an empty account list when no managed accounts are available to the application user. Private instances require a network path from a self-hosted deployment or a self-hosted worker configured for direct routing. The instance must present a trusted TLS certificate. ## Installable workflows The **Privileged Access and Password Management** bundle includes: * **List Password Safe Managed Accounts**: Search account metadata by system or account name. Always returns a list. Providing both names selects one account and ignores pagination. Otherwise, results are limited to 100 accounts per page; use the offset to request another page. * **Request Password Safe Access**: Request time-limited password viewing access with a reason and optional ticket number. Returns a request ID, reusing an eligible existing request for the same application user, system, account, and access type without renewing its duration. Rotation on check-in is requested when creating a request, subject to the account and access policy settings. * **List Password Safe Access Requests**: Find pending requests in the connected user's approver queue. * **Approve Password Safe Request** and **Deny Password Safe Request**: Approve or deny requests raised by other BeyondInsight users, with a recorded reason. * **Check In Password Safe Request**: Check in a request with a recorded reason. * **Rotate Password Safe Account Password**: Generate a new password and update both the managed system and Password Safe. * **Grant Password Safe Group Membership** and **Revoke Password Safe Group Membership**: Add or remove direct BeyondInsight group membership. Removing one membership doesn't remove access granted through other groups. Workflows that change access or passwords require installer approval by default. Request and check-in operations require the appropriate Requestor role; approval and denial require the appropriate Approver role. Password rotation requires **Password Safe Account Management** with full control. Group membership changes require **User Accounts Management** with full control. On Pathfinder, the group-membership workflows can only add or remove application-type users; other user types return HTTP 400. BeyondTrust doesn't allow a user to approve or deny their own request. To act on a request created by **Request Password Safe Access**, run the approve or deny workflow through a second Password Safe connection with a different application user and the required Approver role. Using the requesting connection returns HTTP 403 with BeyondTrust code `4033`. ## Password retrieval and custom workflows The typed API action also supports credential retrieval for an approved request, managed systems, access policies, Smart Rule roles, and privileged sessions. Credential retrieval uses `/BeyondTrust/api/public/v3/credentials/{requestId}`. Check in the request after the consuming operation finishes, including when that operation fails. Retrieving a password doesn't check the request in automatically. The installable workflows return request IDs or account metadata without fetching password values. Custom workflows that retrieve credentials handle sensitive values; don't return those values to help-desk conversations or include them in notifications. ## Troubleshooting * **Authentication fails**: Check the instance host, application-user credentials, API access policy, and source-address restrictions. * **Access is forbidden**: Check the application user's group permissions, the managed account's API access setting, and the applicable access policy. * **A request is pending**: Complete the required approval in BeyondTrust before retrieving credentials, using a different user from the requester. Creating a request doesn't approve it. * **The instance is unreachable**: Check DNS, firewall rules, TLS trust, and the connection's routing configuration. # BeyondTrust Privileged Remote Access Source: https://docs.serval.com/sections/integrations/beyondtrust-pra Connect BeyondTrust PRA to manage remote-access users, asset groups, and vault credentials. Connect **BeyondTrust Privileged Remote Access** to manage remote-access configuration and vault accounts. This integration uses the PRA Configuration API and is available in beta. Depending on your BeyondTrust version, asset groups, asset roles, and asset policies may be labeled Jump Groups, Jump Item Roles, and Jump Policies. For BeyondInsight managed accounts and Password Safe approval requests, connect [BeyondTrust Password Safe](/sections/integrations/beyondtrust-password-safe) separately. ## Before you connect In your PRA `/login` interface, go to **Management > API Configuration** and create an API account. Under **Permissions > Configuration API**, select **Allow Access**. Also select **Manage Vault Accounts** for the vault workflows and the **List Vault Accounts** health check. Record the OAuth client ID, generate a client secret, and save the account. See BeyondTrust's [Configuration API guide](https://docs.beyondtrust.com/pra/reference/configuration-api) and [authentication guide](https://docs.beyondtrust.com/pra/reference/api-guide). ## Connect to Serval In **Integrations > All integrations**, select **BeyondTrust Privileged Remote Access**. * **Instance Host**: Your PRA hostname, such as `access.example.com`. An optional port is supported. Don't include `/login`, another path, or an HTTP URL. * **Client ID**: The API account's OAuth client ID. * **Client Secret**: The API account's OAuth client secret. Run **Test Connection** to authenticate and read PRA user metadata. The instance must be reachable over HTTPS with a trusted TLS certificate. Private instances require a network path from a self-hosted deployment or a self-hosted worker configured for direct routing. ## Installable workflows The **Privileged Access and Password Management** bundle includes: * **Find PRA Users**: Search by email address. * **List PRA Asset Groups**: Search groups by name. * **Grant PRA Asset Group Access**: Add a user to a group with explicit asset role and policy IDs. * **Revoke PRA Asset Group Access**: Remove direct group membership. * **List PRA Vault Accounts**: Search vault account metadata by name. * **Rotate PRA Vault Credentials**: Schedule rotation for supported Windows or AWS vault accounts. * **Check In PRA Vault Account**: Release an account checked out by the API account. Search workflows return one page of up to 100 results. Use the page input to retrieve additional results. Workflows that change access or credentials require installer approval by default. Removing direct asset group membership doesn't remove access inherited through a group policy or administrator permission. Review those grants separately when revoking a user's access. ## Custom workflows The typed Configuration API action supports users, teams, group policies, asset groups and policies, vault accounts, and vault account groups. It includes vault checkout and check-in endpoints. Custom workflows that check out a credential must check it in after use, including on failure. Don't return credential values to help-desk conversations or include them in notifications. The connection manages configuration through the API. Launching remote sessions, Command API calls, and Reporting API downloads aren't included. ## Troubleshooting * **Authentication fails**: Verify the instance host and client credentials. If you generate a new client secret in BeyondTrust, update the Serval connection. * **Access is forbidden**: Verify Configuration API access and the permissions for the requested operation. For vault operations, verify **Manage Vault Accounts** is selected. A successful user-list health check doesn't prove vault or write permissions. * **A user still has access after revocation**: Check inherited group policies and administrator permissions. * **Rotation fails**: Verify that BeyondTrust supports rotation for the account type and that the target system is reachable. # HCL BigFix Source: https://docs.serval.com/sections/integrations/bigfix Connect Serval to your HCL BigFix root server so workflows can look up managed endpoints, evaluate relevance queries, inspect patch content, and take actions. ## About HCL BigFix HCL BigFix manages endpoints at scale: it inventories every computer running the BigFix agent, evaluates patch and compliance content (Fixlets, tasks, and baselines) against them, and deploys actions to fix what is out of policy. This integration connects Serval to your BigFix root server so workflows can find a computer and its reported properties, answer inventory and compliance questions with Session Relevance, list the content that applies to an endpoint, and, when you allow it, take actions. The integration is marked **Beta** in the connect screen, so its capabilities may still change. **Authentication:** Username and password for a BigFix Console operator account, sent to your server as HTTP Basic authentication on each request. Workflows never handle the credentials. **Access level:** You choose what Serval may do when you connect, and Serval enforces it server-side on every request: * **Read-only** lists computers, content, actions, and sites, and evaluates Session Relevance and BigFix Query expressions. * **Full** adds taking actions, managing content, and administering operators and roles. **Data sync:** None. Everything is on demand: Serval calls your server only when a workflow or health check runs. There is no background sync, no webhooks, and no data ingestion. ## What the HCL BigFix integration enables | Capability | Description | | - | - | | BigFix API request | A generic workflow action that can call the supported REST API endpoints: computers and their properties and client settings, relevance queries, actions and their per-computer status, sites, Fixlets, tasks, baselines, analyses, computer groups, retrieved properties, operators, roles, and Web Reports servers. XML responses are converted to JSON automatically. | | Session Relevance query | A workflow action that evaluates a Session Relevance expression, the same language the BigFix Console uses, and returns typed JSON results. | These use the [BigFix REST API](https://developer.bigfix.com/rest-api/) served by the root server on port 52311. The read-only access level is enforced by Serval, not just documented: with it selected, Serval refuses any request to your server that is not a read, so workflows cannot take actions, change content, or modify settings on endpoints. ## Before you connect Two things about your BigFix deployment decide whether a connection can work at all. Check both before creating the operator account. Most BigFix root servers sit on an internal network that Serval's cloud cannot reach. Three deployments are possible: * **Root server reachable from the internet**: connect normally, nothing extra needed. * **Self-hosted Serval deployment**: works when your deployment is configured to allow internal targets. * **Serval cloud with a self-hosted worker**: Enable **Run on self-hosted workers** for the connection. Requests then run from your network; the worker must be able to reach the root server on its REST API port (52311 by default) and trust its TLS certificate. A read-only connection also needs an up-to-date worker: on an older worker every request fails with a message asking you to upgrade it, because the older worker cannot enforce the read-only boundary per request. Serval verifies the server's certificate against its trust store, and there is no option to skip that check or supply a private CA. A root server still serving the self-signed certificate BigFix generates at install time will fail to connect. Replace it with a certificate signed by a CA your Serval deployment trusts, following HCL's guidance on configuring the BigFix server's HTTPS certificate. ## Get your credentials Serval needs your root server's host and a BigFix Console operator account. In the BigFix Console, go to **Tools** then **Create Operator** and create a local operator such as `svc-serval` with a strong password. Using a dedicated account rather than a person's login keeps the connection working when staff change. If your deployment restricts REST API access to LDAP operators, create an LDAP-backed operator instead. A non-master operator only sees the computers and sites assigned to it. Assign the computers Serval should be able to look up, and grant **Reader** access to the sites whose content it should see. For the read-only access level, no further permissions are needed. If you plan to select the **Full** access level so workflows can take actions, also grant the operator the **Can Create Actions** permission and, for custom content, **Writer** access to the relevant sites. Skip this for a read-only connection. Use the hostname or IP address the BigFix Console connects to, without the "https\://" prefix, for example "bigfix.example.com". The REST API listens on port 52311 unless your deployment changed it. ## Connect in Serval In Serval, go to the integrations page and select **HCL BigFix** (marked Beta). Enter the hostname or IP address of your root server, for example "bigfix.example.com". Port 52311 is assumed; add a port only if your server uses a different one. Serval always connects over HTTPS. Enter the operator account, for example "svc-serval", and its password. The password is stored encrypted and shown masked after saving. Select **Read-only** unless workflows need to take actions or manage content. You can change it later in the integration settings. Saving validates the format of what you entered but does not call your server, because the connect screen cannot reach an internal network even when workflows can. Run the health checks afterwards to confirm the credentials work. ## Verifying the connection Four health checks run on demand and are the way to confirm a working connection: | Health check | What it proves | | - | - | | Test BigFix Connection | The credentials are accepted and the server is reachable. | | List BigFix Computers | The operator has been assigned computers to manage. | | Evaluate Session Relevance | The server can forward relevance queries to a Web Reports or BigFix Explorer server. | | List BigFix Sites | The operator can read at least one site. | If Test BigFix Connection passes but List BigFix Computers returns zero computers, the credentials are correct and the operator has no computers assigned. ## Gotchas and troubleshooting The root server does not evaluate Session Relevance itself. It forwards each query to the Web Reports server or BigFix Explorer server with the highest priority, so a deployment without either fails the **Evaluate Session Relevance** health check while every other endpoint keeps working. Install or register one of those components, or use the REST endpoints for computers and content instead. Every list the integration returns is scoped to the operator's permissions. A computer that exists in BigFix but is not assigned to the operator is invisible, as is content in a site the operator cannot read. When a workflow cannot find a computer you know is managed, check the operator's assignments before suspecting the connection. BigFix returns XML, and Serval converts it to JSON with every value kept as a string, so an ID or a count arrives as "538222075" rather than a number. Use the **Session Relevance query** action when you need typed values; its results are returned as JSON with numbers as numbers. The REST API returns complete lists with no paging. On a deployment with tens of thousands of endpoints, listing all computers with their properties is slow and large. Use the fields parameter to limit what comes back, or express the question as a Session Relevance query so the server does the filtering. With the Full access level, a workflow can create an action, which runs ActionScript on every targeted computer once the BigFix agent picks it up. Scope such workflows to explicit computer IDs or a computer group rather than all computers, and prefer Fixlet-sourced actions over inline scripts so the content has been reviewed in the console. Serval sends the stored password on every request. If the operator's password is rotated or the account is disabled in BigFix, requests fail with an authentication error. Update the password in the integration settings to restore it. The HCL BigFix connect tile is marked Beta, so the available actions may still change. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your HCL BigFix integration. # BigPanda Source: https://docs.serval.com/sections/integrations/bigpanda Connect BigPanda to Serval with a single API token so workflows can manage incidents, alerts, environments, and more through the BigPanda API. ## About BigPanda BigPanda is an AIOps and incident intelligence platform that correlates monitoring alerts into incidents. The Serval BigPanda integration connects with one API token: an admin pastes a BigPanda Bearer token, and Serval makes calls to the BigPanda API on your workflows' behalf through the built-in **BigPanda API request** action. Serval automatically routes each call to the correct BigPanda API host and attaches your token, so there is nothing technical to configure beyond pasting the token. **Authentication:** API token (a BigPanda Bearer token - a User API Key, a Service Account Key, or the org-wide Org Token) **Data sync:** On-demand only. Connecting BigPanda does not import incidents, alerts, or any other records into Serval, and there are no background syncs, webhooks, or auto-installed workflows - all access happens when a workflow runs a BigPanda action. ## What the BigPanda integration enables | Capability | Description | | - | - | | Incident management | List and retrieve incidents by environment, add comments, resolve, snooze, assign, merge, and split incidents, batch-resolve alerts, read incident activity, and manage incident tags and tag definitions. | | Alert ingestion and retrieval | Send alert monitoring events into BigPanda, send normalized alerts to Open Integration Manager integrations, and retrieve raw integration alerts. | | Environments and groups | Create, list, update, and delete environments and environment groups. | | Changes and root cause correlation | Create, update, and retrieve change records, and manage related-change correlations. | | Alert enrichment | Manage alert enrichments, enrichment configuration and tags, mapping enrichments and map uploads, and check enrichment job status. | | Correlation patterns | Create, list, update, delete, and reorder correlation patterns. | | Maintenance plans | Create, list, update, and stop maintenance plans, including ordered plans and planned maintenance schedules. | | AI analysis | Trigger or read AI analysis for an incident and manage AI analysis configurations. | | Inbound integration configuration | Manage Open Integration Manager and email parser configurations, data connectors, and BigPanda integrations themselves. | | Administration | Manage SCIM users, roles, API keys and service-account API keys, and read audit logs, topology models, and troubleshooting logs. | Anything in the integration's modeled surface of the [BigPanda API](https://api-docs.bigpanda.io/) can be accessed through Serval. This covers both the primary REST API (`api.bigpanda.io`) and the Open Integration Manager / ingestion endpoints (`integrations.bigpanda.io`). ## Get your credentials Serval accepts any BigPanda Bearer token. For most teams, that means a BigPanda API key - either a **User Key** (tied to your BigPanda user and its roles) or a **Service Account Key** (shared, not tied to a person). If your workflows focus on sending alert data into BigPanda, you may need the org-wide **Org Token** instead - see the gotchas below for which endpoints document which token type. See BigPanda's [API Key Management](https://docs.bigpanda.io/en/api-key-management) guide for full details. Sign in to BigPanda as a user whose role grants the "API Keys" permission with Full Access (configured under Roles Management). Open the **API Keys** page in BigPanda Settings and select the **New key** button. Select **User Key** (carries your user's roles and permissions) or **Service Account Key** (shared, not tied to a person - best for team automation). Enter a Key Name, choose a key expiration (6 months, 12 months, 24 months, or no expiration), select a user to notify before expiration, and optionally add a description (up to 1000 characters). Select **Create Key** and copy the key immediately. BigPanda displays a new API key exactly once and does not store a copy. If you lose it, you must create a new key and reconnect. Sign in to BigPanda as an administrator with integrations access. Open the **Integrations** tab in BigPanda. Your org's Bearer token appears in the example headers of any Alerts API integration's instructions. See BigPanda's [Authentication and Headers](https://docs.bigpanda.io/en/authentication-and-headers) guide. The Org Token is org-wide. BigPanda documents it as the required token type for sending alert monitoring events, the legacy v1 incident endpoints, the alert filter plan and schedule endpoints, and the Open Integration Manager and email parser configuration endpoints. For everything else, a User Key or Service Account Key is the better choice - it gives better audit logging and scoped permissions. Serval does not track your BigPanda key's expiration date. Set a notification user when creating the key so someone is warned before it expires, and rotate it in Serval when it does. ## Connect in Serval In Serval, open the **BigPanda** integration's connect form. Paste your BigPanda Bearer token into the **API Token** field (a masked password field). The form recommends a User API Key for better audit logging and scoped permissions, but an Org Token also works. Submit the form to finish connecting. Serval's BigPanda integration targets BigPanda's US API hosts (`api.bigpanda.io` and `integrations.bigpanda.io`). The hosts are fixed - there is no field to select a region, and EU-hosted BigPanda orgs are not supported. If your organization is hosted in BigPanda's EU environment, contact Serval support before connecting. Serval performs no validation on the API Token field when you connect - the field is not marked required, there is no format check, and no test call is made. A mistyped or expired token will not produce an error here; it surfaces later as failed workflow runs. When you reopen the connection settings, the stored token is shown obfuscated (bullet characters plus its last 4 characters). Saving the form with the field blank or still obfuscated keeps your existing token unchanged - you only need to paste a new value when rotating the token. ## Verifying the connection The BigPanda integration ships no in-product health checks - no health checks section appears on the integration settings page, and connection problems surface as failed workflow runs instead. To confirm your token works, run a workflow that uses the **BigPanda API request** action to make a simple read-only call - listing your BigPanda environments is a good lightweight choice - and check that the run succeeds. If a simple read-only call succeeds but a specific call fails with a 401 or 403 error, the connection is fine - the stored token's type or its user's BigPanda permissions do not cover that particular API. See the gotchas below. ## Gotchas and troubleshooting Serval stores exactly one token and sends it on every call, but BigPanda documents different required token types per API family. Most resource APIs - incidents, environments, changes, enrichment, correlation patterns, maintenance plans, and the administration endpoints - document the User API Key type. The endpoint for sending alert monitoring events, the legacy v1 incident endpoints, the alert filter plan and schedule endpoints, and the Open Integration Manager and email parser configuration endpoints document the org-wide Org Token instead. If your workflows mix families that need different token types, calls outside your stored token's family fail with 401 - reconnect with the other token type, or split usage across connections. Open Integration Manager ingestion calls also reference a BigPanda integration app key created during BigPanda inbound-integration setup; the Bearer token alone is not sufficient there. A User Key carries all roles and permissions of its associated BigPanda user, so endpoint-specific 401/403 errors usually mean the key's user lacks the relevant BigPanda permission. For shared automation that should not depend on one person's account, create a Service Account Key instead and reconnect with it. Because there is no data sync and no in-product health check, nothing alerts you proactively when the token expires or is revoked - the first symptom is failed workflow runs. Key expiration (6, 12, or 24 months, or none) is managed entirely in BigPanda; rotate the key there and paste the new value into the Serval connection. BigPanda shows a newly created API key exactly once and does not store a copy. If you lose it, create a new key in BigPanda and update the Serval connection with the new value. BigPanda serves most of its API from its primary host (`api.bigpanda.io`) but serves Open Integration Manager configuration, email parser configuration, data-connector settings, and normalized-alert ingestion from a second host (`integrations.bigpanda.io`). Serval routes each call to the right host automatically and sends the same Bearer token to both - you never specify a host yourself. Both hosts are BigPanda's US endpoints; EU-hosted orgs are not supported. The settings form shows the stored token obfuscated (bullets plus the last 4 characters) with a pencil icon for entering a replacement; canceling the edit restores the obfuscated value. Submitting the form with the field blank or still obfuscated keeps the existing token - you only need to re-paste a token when rotating it. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your BigPanda integration. # Box Source: https://docs.serval.com/sections/integrations/box Connect Box, the cloud content management platform, to Serval so your workflows can work with folders, collaborations, users, and groups, manage Box Hubs, generate documents with Doc Gen, and administer your Box enterprise on demand. ## About Box Box is a cloud content management platform for secure file storage, sharing, and governance. The Serval Box integration connects your Box account so workflows can work with folders, files, collaborations, users, and groups, plus Box Hubs, Box Doc Gen, and enterprise administration settings live, as they run. **Authentication:** Two options - **Sign in with Box** (OAuth 2.0, labeled Recommended), which uses a Serval-managed Box app with selectable permission presets, or **Client Credentials Grant**, which uses your own Box Platform App and authenticates as your enterprise's Service Account or as a specific Box user. **Data sync:** Workflows call the Box API live, on demand (all traffic goes to api.box.com). One scheduled sync exists, opt-in per connection: **knowledge sync**, which ingests documents from the folders you explicitly select as knowledge. Sign in with Box connections refresh their access token automatically as it nears expiry; Client Credentials connections mint a fresh short-lived token on every request, because Box issues no refresh tokens for that grant type. ## What the Box integration enables | Capability | Description | | - | - | | Generic Box API access | Workflows can reach any part of the Box API through a single Serval-managed action, with authentication handled for you. | | Folders and files | Read folder details, list a folder's contents, search across content, and read file details or download file content. | | Collaborations | Grant, inspect, update, and remove folder-level access for users and groups — the building block for access-request workflows against Box folders and data rooms. | | Knowledge source | Sync documents from selected Box folders into the team knowledge base: Markdown and other text formats, plus PDF, Word, and PowerPoint. Nothing syncs until a folder is explicitly selected. | | Users and groups | List and look up enterprise users, and read groups and group memberships. | | Box Hubs | List, create, get, update, copy, and delete Box Hubs; add and remove Hub items; list enterprise Hubs; and manage Hub collaborations for users and groups. | | Box Doc Gen | Mark files as Doc Gen templates, list templates and template tags, generate documents in batches, and track Doc Gen jobs by job, template, or batch. | | Enterprise administration | Read enterprise configuration (security, content and sharing, user settings, shield); manage shield lists; create, update, and delete archives; and submit external-user deletion jobs. | | OAuth permission presets | Connect-time checkboxes that map to [Box scopes](https://developer.box.com/guides/api-calls/permissions-and-errors/scopes): Read Files and Folders (checked by default), Read and Write Files and Folders, Manage Users, Manage Groups, Manage Webhooks, Enterprise Administration, Box Sign, and Box AI. | Anything defined in the [Box API](https://developer.box.com/reference) can be accessed through Serval. ## Get your credentials Which setup you need depends on the connection method you choose. **Sign in with Box** requires nothing created on the Box side - Serval uses its own managed Box app and you simply sign in and approve. **Client Credentials Grant** requires a Box Platform App that you create and a Box admin authorizes; see the [Box Client Credentials Grant guide](https://developer.box.com/guides/authentication/client-credentials/) for background. No credentials to create. You will sign in with your Box account and choose permission presets directly in the Serval connect dialog. Effective permissions are capped by what your Box account can do, and the presets you pick are fixed at connect time. Choose the presets your workflows will need before you authorize - changing them later means reconnecting. Go to the [Box Developer Console](https://app.box.com/developers/console), open **Platform Apps**, and click **New App**. Enter an app name and select **Client Credentials Grant** as the app type. Box does not let you change an app's authentication method later, so pick Client Credentials Grant from the start. In the app's **Configuration** tab, set the **App Access Level** and enable the **Application Scopes** your workflows need, then save your changes. With this method, permissions live on the Box app, not in Serval. If you plan to connect as a specific Box user rather than the Service Account, also enable **App + Enterprise Access** and **Generate User Access Tokens** on the Configuration tab - Box will not issue user tokens without them. Both are on the **Configuration** tab. Box requires two-factor authentication on your account before it will reveal the Client Secret. On the app's **Configuration** tab, a Box Admin or Co-Admin can click **Authorize** directly; anyone else clicks **Submit** to send an authorization request. Admins manage approvals in the Box Admin Console under **Integrations**, then [**Platform Apps Manager**](https://app.box.com/master/platform-apps). Until an admin authorizes the app, Box rejects its credentials and the Serval connection cannot be saved. Your Enterprise ID is shown in the Box Admin Console under **Account & Billing**. If you plan to connect as a specific Box user instead of the Service Account, note that user's Box User ID from the Admin Console's **Users & Groups** page. See [Box user types](https://developer.box.com/platform/user-types) for the difference. ## Connect in Serval Find **Box** and start a new connection. The **Connect Box** dialog opens with the two connection methods. It is labeled **Recommended** in the method selection dialog. This option only appears when platform integration OAuth is enabled for your organization. If it is not, the dialog opens directly on the Client Credentials Grant form instead. **Read Files and Folders** is checked by default. Check any additional presets your workflows need - they are fixed once you authorize. Click **Connect Account** and complete the Box sign-in and consent screen. Serval then names the connection after your Box enterprise; personal (non-enterprise) Box accounts are supported too, in which case the connection is named after your email domain. After connecting, the connection's settings page lists the permissions Box actually granted under **Current Scopes** and offers a **Reconnect** button for re-running the flow with different presets. Find **Box**, start a new connection, and choose the Client Credentials Grant method. The dialog title changes to **Configure Box**. Placeholder: "e.g., My Box Integration". If left blank, Serval names the connection "Box (enterprise)" or "Box (user)" based on your Subject Type. Placeholder: "From Box Developer Console". Paste the Client ID from your app's Configuration tab. Placeholder: "From Box Developer Console". Paste the Client Secret. This is a password field. A dropdown with exactly two options: **Enterprise (Service Account)** and **User**. It defaults to Enterprise. Helper text: "Enterprise authenticates as the app's Service Account. User authenticates as a specific Box user." Placeholder: "Your Box Enterprise ID or User ID". Helper text: "Enter your Enterprise ID if using Enterprise subject type, or the User ID if using User subject type." Click **Submit**. Serval validates your credentials by fetching a real token from Box before the connection is created. If any required field is blank, the form blocks submission with "Please fill in all required fields". If Box rejects the credentials, the dialog shows an error beginning with "Failed to install integration" followed by the specific reason - see the troubleshooting section below for the most common causes. To edit a Client Credentials connection later, open the connection's settings page and click **Reconnect**. The Configure Box form opens prefilled with your saved values, with the Client Secret masked. Leave the masked value to keep your existing secret, or paste a new one to replace it; any field you change is validated with a live token fetch from Box before it is saved, and fields you leave alone keep their stored values. ## Verifying the connection Box does not surface named health checks in Serval - the **Health Checks** section that appears on some integrations' settings pages is not shown for Box, and there is no built-in connection test with success or failure messages. The most direct way to confirm the connection works end to end is to run a quick read-only workflow against Box - for example, one that lists the items in a folder - and check that it returns data. Your Serval team or Catalyst can set one up in a couple of minutes. For Sign in with Box connections, the settings page also lists the permissions the connection holds under **Current Scopes** - the fastest way to confirm the right presets were granted. A working token does not mean every workflow will succeed. The most common follow-on failure is a permissions gap: for Sign in with Box connections, a preset you did not check at connect time; for Client Credentials connections, an Application Scope not enabled (and saved) on the app in the Box Developer Console, or content the Service Account has never been invited to. ## Gotchas and troubleshooting Serval mints a real token from Box before saving the connection, and when Box rejects the attempt the dialog shows the reason - an error that includes "failed to validate Box credentials" and the detail Box returned. The most common cause is an app no Box admin has authorized yet: submit it from its **Configuration** tab and have an admin approve it in the [Box Admin Console's Platform Apps Manager](https://app.box.com/master/platform-apps), then try again. A wrong Enterprise ID or User ID, a Subject Type that does not match the ID you entered, or a rotated Client Secret all fail the same way. With Subject Type **Enterprise**, calls run as the app's Service Account - a separate identity with its own folder tree. It sees no user content unless that content is explicitly shared (collaborated) with it. Either collaborate the Service Account into the folders you need, or connect with Subject Type **User** as a specific Box user - which additionally requires **App + Enterprise Access** and **Generate User Access Tokens** enabled on the app's Configuration tab. See [Box user types](https://developer.box.com/platform/user-types). OAuth permissions are fixed at connect time: Serval requests read access to files and folders by default plus whichever presets you checked, and records what Box actually granted. To change permissions, open the connection's settings page, review **Current Scopes**, and click **Reconnect** to re-run the flow with new presets. Permissions are always capped by what the authorizing Box user can do. Open the connection's settings page and click **Reconnect**. The Configure Box form opens prefilled with the saved Instance Name, Client ID, Subject Type, and Enterprise/User ID, and the Client Secret shown as a masked placeholder. Paste a new secret to rotate it, or leave the masked value untouched to keep the existing one. Submitting validates the resulting credentials with a live token fetch from Box; if Box rejects them, the dialog shows an error beginning with "Failed to update integration" and nothing is overwritten. If token minting fails during a workflow request on a Client Credentials connection, the run shows: "Box authentication failed for '\[instance name]'. Please verify your credentials in Box Developer Console. Error: \[details]". Check that the app is still authorized by your Box admin and that its Client Secret has not been rotated; if the secret changed, click **Reconnect** on the connection's settings page and paste the new value. Workflows reach Box through a single Box API request action. Its typed, documented catalog covers the classic endpoints for folders, files, collaborations, search, users, and groups, plus Box's 2025.0 endpoint set: Hubs, Doc Gen, enterprise configuration, shield lists, archives, and external-user deletion jobs. Operations beyond that - for example metadata templates, webhooks, or Box Sign requests - are not yet callable from workflows; contact Serval if you need one and we can extend the catalog. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Box integration. # Brex Source: https://docs.serval.com/sections/integrations/brex Connect Brex, the corporate card and spend-management platform, so Serval workflows can read and manage your users, cards, expenses, budgets, payments, and transactions on demand. ## About Brex Brex is a corporate card and spend-management platform. Serval's Brex integration connects with a single Brex user API token and covers nine areas of the Brex platform - team, expenses, budgets, transactions, payments, accounting, travel, custom fields, and onboarding - so your workflows can read and update Brex data whenever they run. Everything happens live against Brex; there is nothing to import or schedule. **Authentication:** Brex user API token, pasted into Serval and sent as a secure bearer credential on every request. There is no OAuth sign-in flow. **Data sync:** On demand only. Serval contacts Brex exclusively when a workflow step runs - there is no background sync, no polling schedule, and no webhooks from Brex. ## What the Brex integration enables | Capability | Description | | - | - | | Team, users, and cards | View, invite, and update employees (including setting per-user monthly limits); view and create departments, locations, and titles; view legal entities and company details; and manage cards - including create, update, lock, unlock, and terminate. | | Expenses | List, review, and update expenses, match receipts to card expenses, and upload receipts. | | Budgets and spend limits | Create, view, update, and archive budgets and spend limits, and create, update, or delete budget programs. | | Accounts and transactions | List card and cash accounts, statements, and transactions. | | Payments and vendors | Create and view transfers, create incoming transfers to fund your Brex account, view linked accounts, and manage vendors. | | Accounting | Set up, disconnect, and reactivate accounting integrations, query accounting records, and report export results. | | Travel | View trips and their bookings. | | Custom fields | Manage custom field definitions and their values. | | Onboarding | Create and track referrals and upload referral documents. | Anything defined in the [Brex API](https://developer.brex.com) can be accessed through Serval. ## Get your credentials Serval connects to Brex with a user API token that you generate in the Brex dashboard. The token's enabled permission scopes determine exactly what Serval can read or write - nothing more. See the [Brex authentication documentation](https://developer.brex.com/docs/authentication/) for background, or the [Brex Developer Portal](https://developer.brex.com) for the full platform reference. Open the [Brex Dashboard](https://dashboard.brex.com) and sign in. Navigate to **Developer > Settings** in the Brex dashboard - the [developer settings page](https://dashboard.brex.com/settings/developer). Click **Create Token** and enter a descriptive name, for example "Serval Integration". Choose the scopes your workflows need. At minimum, grant read access for **Users**, **Cards**, **Card Accounts**, and **Departments** - these four are required for Serval's connection health checks to pass. Click **Allow Access**, then copy the token right away and keep it somewhere safe until you paste it into Serval. Brex shows the token only once, at creation time. If you navigate away without copying it, you will need to create a new token. Grant write scopes only if your workflows will create or modify Brex data (for example, creating budgets or locking cards). Read-only scopes are enough for reporting and lookup workflows. ## Connect in Serval In Serval, add a new connection and choose **Brex**. Paste the token into the **API Token** field. It is the only field, it is required (marked with an asterisk), and it hides what you type like a password. The helper text under the field reads "Generate a user token from your Brex dashboard at Developer > Settings". Paste carefully: the form does not check the token when you submit, so even a blank or mistyped value saves successfully. Save the form. If saving fails, you may see "Failed to install integration" or "Failed to save configuration. Please try again." Run the connection health checks immediately after saving (see below). Serval does not test the token against Brex when you save - any value is accepted - so the health checks are your first real confirmation that the token works. When you reopen the connection settings later, the saved token appears as a masked value (bullet characters plus its last 4 characters) with a control to replace it - a **Replace** button or a pencil icon, depending on where you edit. Clicking it opens a password input with the placeholder "Enter new value". Any time you save this connection's settings again - whether you are rotating the token or just re-saving the form - use that control and paste the complete token before saving. Do not save with the field blank or with only the masked value showing. If an update fails, Serval shows an error starting with "Failed to update integration:" or the message "Failed to update configuration". ## Verifying the connection The Brex integration ships four health checks. Run them right after connecting and after any edit to the connection. **List Brex Users** - confirms the token is valid and can list the users in your Brex account. * Success: "Successfully listed users from Brex (sample size: \[number])" * Failure: "Unable to list users from Brex. Please verify your API token is valid and has the 'users.read' scope enabled." **List Brex Cards** - confirms the token can list cards. * Success: "Successfully listed cards from Brex (sample size: \[number])" * Failure: "Unable to list cards from Brex. Please verify your API token has the 'cards.read' scope enabled." **List Brex Card Accounts** - confirms the token can list card accounts. * Success: "Successfully listed card accounts from Brex (count: \[number])" * Failure: "Unable to list card accounts from Brex. Please verify your API token has the 'accounts.card.read' scope enabled." **List Brex Departments** - confirms the token can list departments. * Success: "Successfully listed departments from Brex (sample size: \[number])" * Failure: "Unable to list departments from Brex. Please verify your API token has the 'departments.read' scope enabled." Each check needs its own Brex scope, so a mix of green and red checks means the token is valid but missing specific scopes - not that the connection is broken. Likewise, all four checks can pass and a workflow can still fail if it touches an area the checks do not cover (for example, expenses or budgets). Grant the missing scope in the Brex dashboard; if that means creating a new token, update the connection in Serval and paste the complete new token. ## Gotchas and troubleshooting The token appears masked when you open the connection settings. Saving the form without replacing the masked value with the complete token can leave the connection without a working credential, and workflows will start failing. Whenever you edit this connection for any reason, click the replace control, paste the entire token (or the new one, if rotating), save, and confirm all four health checks pass. Serval accepts whatever you paste at install time - a typo, a truncated paste, an already-revoked token, or even an empty field will all save successfully. The problem only surfaces when the health checks run or a workflow calls Brex. Always run the health checks immediately after connecting. Access is exactly the token's enabled Brex scopes, evaluated per area. A token can pass the users check yet fail the cards check, or pass all four health checks yet fail on an expenses workflow. If a workflow gets permission errors from Brex, grant the relevant scope in the Brex dashboard; if you create a new token to do it, update the connection in Serval with the full new token. Brex list results are paginated with a cursor: each response includes a batch of items plus a pointer to the next page. A single workflow step returns only one page, so workflows that need everything must loop and follow the next-page cursor until there are no more pages. If a workflow seems to be "missing" records, pagination is the usual cause. Serval attaches your token exclusively to requests bound for Brex's official API hosts: platform.brexapis.com and its secure companion host, secure-platform.brexapis.com (the host Brex uses for PCI-sensitive card-number retrieval). The integration's built-in actions all target Brex's main API host; requests to any other destination never receive the credential. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Brex integration. # Brivo Source: https://docs.serval.com/sections/integrations/brivo Connect Serval to Brivo Access so workflows can manage cardholders, credentials, and access groups through Brivo's OAuth API. ## About Brivo Brivo Access is a cloud physical-access platform for cardholders, credentials, sites, and access groups. The Serval Brivo integration is in **Beta**. Each connection maps to one Brivo account in either the US (`access.brivo.com`) or EU (`access.eu.brivo.com`) environment. **Authentication:** Customer-provided OAuth 2.0 application plus a Mashery API key. You create the application in Brivo Marketplace (authorization\_code and refresh\_token grants), paste the Client ID, Client Secret, and API key into Serval, and approve access in Brivo. Serval refreshes access tokens automatically. Brivo access tokens expire after five minutes, so refresh is required on nearly every call. **Data sync:** On-demand only. Workflows call the Brivo Access API when they run. Four health checks verify accounts, users, access groups, and sites. ## What the Brivo integration enables | Capability | Description | | - | - | | Workflow API access | Workflows can call Brivo Access API operations on demand, covering accounts, users (cardholders), credentials, access groups, and sites. | | User and group management | Create, update, and delete users; add or remove users from access groups; assign or unassign credentials. | | Connection health checks | Four automated checks verify account, user, access group, and site list access after connecting. | Anything defined in the [Brivo Access API](https://apidocs.brivo.com) can be reached through the generic request action. Auth headers are injected by Serval; do not put the API key or bearer token in workflow code. ## Get your credentials In [Brivo Access](https://access.brivo.com) (or [access.eu.brivo.com](https://access.eu.brivo.com) for EU accounts), open Marketplace and choose **Generate API Token**. Name the application, select the 3-legged / authorization\_code grant, and enable the refresh\_token grant. Password grant cannot be combined with authorization\_code. Add this redirect URI to the application: `https://svflow-auth-config.api.serval.com/brivo/oauth/callback` Self-hosted Serval deployments use `https://svflow-auth-config.api./brivo/oauth/callback` instead. The connect dialog also shows the exact URI for your environment. Open the enabled application in Marketplace and copy both values. From [developer.brivo.com](https://developer.brivo.com/apps/mykeys), copy an API key for the same environment as the account (PROD vs EU). A `Developer Inactive` response usually means the key is missing, wrong, or for the other environment. Production keys are issued by Brivo; developer keys are capped at 25,000 calls per month. Treat the Client Secret and API key like passwords. Serval stores them to refresh tokens and to sign API calls, and only shows obfuscated values later. ## Connect in Serval Find Brivo in the Serval app catalog (it is labeled Beta) and start the connection. Match the Brivo account: US uses `auth.brivo.com` and `api.brivo.com`; EU uses `auth.eu.brivo.com` and `api.eu.brivo.com`. All three fields are required. Register the displayed redirect URI on the Brivo application before connecting. Serval redirects to Brivo to sign in and approve access. Finish within 10 minutes of clicking Connect. Brivo connections cannot be edited in place. To rotate the Client Secret or API key, reconnect and re-enter the values. ## Verifying the connection | Check | What it verifies | | - | - | | List Accounts | Serval can list Brivo accounts. | | List Users | Serval can list cardholders. | | List Access Groups | Serval can list access groups. | | List Sites | Serval can list sites. | ## Gotchas and troubleshooting Brivo requires `grant_type=refresh_token` with Basic client credentials and the `api-key` header on `auth.brivo.com`. Custom integrations only offer API key, OAuth client credentials, or delegated OIDC, and cannot store a refresh token together with client credentials. Use this native integration instead. The Mashery `api-key` header is missing or does not match the environment. Confirm the key from developer.brivo.com is for US or EU, matching the environment selected at connect time. The Marketplace application must include the `refresh_token` grant. Create a new application with authorization\_code and refresh\_token, then reconnect. Credentials entered in the connect dialog are held for 10 minutes. Start the flow again and finish Brivo approval promptly. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Brivo integration. # Buildkite Source: https://docs.serval.com/sections/integrations/buildkite Serval's Buildkite integration lets you automate CI/CD operations and manage **team membership** in your Buildkite organization. The integration connects via a Buildkite API access token scoped to your organization. *** ## What is Buildkite? [Buildkite](https://buildkite.com) is a CI/CD platform for running builds on your own infrastructure or Buildkite-hosted agents. Organizations use **teams** to control who can access pipelines, test suites, and related resources. Team members are assigned a **member** or **maintainer** role. *** ## What Serval can do once connected | Capability | Description | | - | - | | Access Management | Request and provision **Member** or **Maintainer** access to Buildkite teams; sync team membership into Serval | | Automation workflows | List teams, manage team members, and call any endpoint in the [Buildkite REST API v2](https://buildkite.com/docs/apis/rest-api) subset exposed by the integration | Users must already be **organization members** in Buildkite before they can be added to a team. Serval does not invite new org members through this integration. *** ## Configure Buildkite ### Prerequisites * A Buildkite organization you can administer * Permission to create an API access token with team-management scopes * Target users must already exist as members of the Buildkite organization ### Create an API access token 1. In Buildkite, open **Personal Settings → API Access Tokens** 2. Click **New API Access Token** 3. Configure the token: * **Description**: e.g. `Serval Integration` * **Organization access**: limit to the organization Serval should manage * **REST API scopes** — under **Organization & Users**, enable the permissions below (see screenshot) 4. Create the token and copy the value — it is only shown once For details, see [Managing API access tokens](https://buildkite.com/docs/apis/managing-api-tokens). ### Suggested permissions Buildkite API token permissions: Organizations Read, Teams Read and Write, User Read | Resource | Read | Write | | - | - | - | | Organizations (`read_organizations`) | ✅ | — | | Teams (`read_teams`, `write_teams`) | ✅ | ✅ | | User (`read_user`) | ✅ | — | ### Scope reference | Scope | Used for | | - | - | | `read_teams` | List teams, read team membership, healthchecks | | `write_teams` | Add users to teams, change roles, remove team members | | `read_organizations` | Look up organization members by email when provisioning access | | `read_user` | Validate the API token during connection healthchecks | *** ## Serval Configuration 1. In Serval, go to **Integrations → All integrations → Buildkite → Connect** 2. Enter: | Field | Description | | - | - | | Organization Slug | Your Buildkite org slug (from the org URL, e.g. `my-company` in `buildkite.com/my-company`) | | API Access Token | The token you created above | 3. Click **Save** Serval validates the connection and runs healthchecks for authentication, team listing, and organization member listing. Once verified, the integration shows **Healthy** on the Integrations page. ### Access Management After connecting: 1. Enable **resource sync** for Buildkite teams on the application settings page 2. Serval ingests teams as requestable resources with **Member** and **Maintainer** entitlements 3. Users can request access through your normal Serval access workflows; approved requests add or update the user's team membership in Buildkite ### Managing access later * **Rotate token** — Create a new API access token in Buildkite, then update the token in Serval's integration settings * **Disconnect** — Remove the integration from Serval; revoke the token in Buildkite *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Buildkite integration. # Calendly Source: https://docs.serval.com/sections/integrations/calendly Connect Calendly to Serval with a personal access token so workflows can read scheduled meetings, check availability, manage your organization, and act on anything in the Calendly API. ## About Calendly Calendly is a scheduling automation platform for booking meetings and managing availability. The Serval Calendly integration lets your workflows read and act on Calendly data - scheduled events and invitees, event types and availability, organization members and invitations, scheduling links, routing forms, and webhook subscriptions. Serval only ever talks to Calendly's official API address (api.calendly.com), using the token you provide. **Authentication:** Personal access token (API key). An admin generates a token in Calendly and pastes it into Serval's connect form. There is no OAuth flow - the token stays valid until you revoke or replace it in Calendly. **Data sync:** On-demand only. Serval reads from and writes to Calendly exclusively when a workflow runs. There is no background sync, no entity ingestion, and no prebuilt workflows are installed with this integration. ## What the Calendly integration enables | Capability | Description | | - | - | | See scheduled meetings | List and read scheduled events, see each event's invitees, cancel events, and mark or clear invitee no-shows. | | Check event types and availability | Look up a user's event types, their details and hosts, and available times; create one-off event types; and read availability schedules and busy times. | | Manage organization membership | See who belongs to your Calendly organization, remove members, send or revoke organization invitations, and read groups and group memberships. | | Share scheduling links | Create single-use scheduling links and shares. | | Read routing forms | List and read routing forms and their submissions. | | Notify other systems via webhooks | List, create, read, and delete Calendly webhook subscriptions, and fetch sample webhook payloads. | | Audit and data compliance | Read organization activity log entries and request compliance deletion of invitee or scheduled-event data. | Anything defined in the [Calendly API](https://developer.calendly.com/api-docs) can be accessed through Serval. ## Get your credentials You need a Calendly personal access token, generated from a Calendly account that can see the meetings, event types, and members your workflows will need - often an organization owner/admin or a dedicated service account. See the [Calendly API documentation](https://developer.calendly.com/api-docs) for background. Log in to your Calendly account. Go to **Integrations**, then **API & Webhooks**, or open it directly at [calendly.com/integrations/api\_webhooks](https://calendly.com/integrations/api_webhooks). Under **Personal Access Tokens**, click **Get a token now** (or **Generate new token** if you already have tokens). Enter a name for the token (e.g. "Serval Integration"). Click **Create Token**, then **Copy token**. Calendly shows the token only once. Copy it immediately - you cannot retrieve it later. The token acts as the person who created it. Serval can only see the meetings, event types, and members that account can see, within that account's organization. For broad coverage, generate the token from an organization owner/admin or a dedicated service account. ## Connect in Serval In Serval, add the **Calendly** integration to open the connect form. Fill in **Instance Name** - "A friendly name for this Calendly integration instance (e.g., "Production Calendly")". The name also becomes the connection's internal identifier, so pick a stable, meaningful name up front, give each Calendly connection a distinct one, and treat it as permanent. Fill in **Personal Access Token** - "A personal access token generated for your Calendly account." This is a password-style field; after saving, Serval shows it masked, with only the last 4 characters visible. Save the connection. Neither field shows inline validation messages, so a blank or mistyped token is accepted at save time - if the save itself fails you will see a general error such as "Failed to connect service" or "Failed to install integration". Serval does not run a connection check when you save. A wrong or revoked token will not be flagged here - it surfaces the first time a workflow calls Calendly. Verify the connection right after saving (see below). ## Verifying the connection The Calendly integration has no automated health checks in Serval, so nothing runs after you connect and there is no pass/fail status to look for. To verify the connection: 1. Create or run a simple workflow that reads Calendly data - for example, one that lists your scheduled meetings or event types. 2. If the workflow returns Calendly data, the token works. 3. If it fails with an authentication or authorization error, generate a fresh token in Calendly and re-enter it in the connection settings. If a basic read works but a specific workflow still fails, check what the token's owner can actually see in Calendly. The token is limited to that person's visibility and organization - meetings or members outside their view are invisible to Serval. ## Gotchas and troubleshooting When updating this connection's settings (including rotating the token), always re-enter the full **Personal Access Token** before saving, and do not clear or blank out any pre-filled field. If the connection stops working after an edit, re-enter the token and save again. Errors during an edit appear as messages like "Failed to update configuration", "Failed to update integration: \[error message]", or "Failed to save configuration. Please try again." Calendly has no health checks in Serval, so a mistyped or revoked token is not caught at connect time - it surfaces the first time a workflow calls the Calendly API. Generate a new token in Calendly, re-enter it in the connection settings, and re-run the workflow. The token acts as the person who created it. Serval sees only what that person can see, inside their Calendly organization. If workflows need broader visibility, generate the token from an organization owner/admin or a dedicated service account. If the issuing person leaves or their access changes, the token can stop working - rotate to a new token. Calendly shows the token only once, and Serval stores it masked (only the last 4 characters visible) - it can be replaced but never revealed. Generate a new token in Calendly and enter it in the connection settings. The **Instance Name** field appears pre-filled on the connection's settings page, but it doubles as the connection's internal identifier (derived from the lowercased name), so saving a new name silently changes that identifier - Serval offers no safe way to rename an existing connection. Leave the pre-filled name exactly as it is whenever you edit or reconnect. To use a different name, set up a new connection - and because the identifier comes from the lowercased name, give each Calendly connection on a team a distinct name so two connections never collide internally. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Calendly integration. # Cerby Source: https://docs.serval.com/sections/integrations/cerby Connect Cerby to Serval with a workspace API token so workflows can read account inventory, retrieve passwords and TOTP codes, manage users, teams, collections, and secrets, and drive provisioning in Cerby's business hub integrations. ## About Cerby [Cerby](https://cerby.com) is an identity, access, and password management platform for "disconnected" applications - apps without SSO or SCIM support, and seat-licensed social and marketing tools. Connecting Cerby to Serval lets workflows read your account inventory and MFA state, retrieve passwords and TOTP codes from Cerby-managed vaults, manage users, teams, collections, and secrets, and drive user provisioning and entitlement changes in Cerby's connected business hub integrations. Serval talks only to your own workspace's Cerby address (for example acme.cerby.com) and attaches your API token to every request. **Authentication:** API key (a Cerby workspace API token plus your workspace name) **Data sync:** On-demand only. There is no background sync, resource import, or scheduled polling - Serval calls Cerby only when a workflow runs, and verifies the connection with lightweight read-only health checks. ## What the Cerby integration enables | Capability | Description | | - | - | | Account inventory and secret reads | List all accounts, retrieve an account by id, list the users on an account, read an account's password (only for accounts stored in an AWS KMS vault), and retrieve the account's current TOTP code. | | Account and secret sharing | Share accounts with users or teams; list, create, and retrieve secrets; list and share a secret's user and team members. | | Collection management | List collections, retrieve, update, or delete a collection, add resources to a collection, list subcollections, and list, add, or remove the accounts, secrets, users, and teams in a collection. | | User management | List and create workspace users, retrieve and update a user, and list a user's accounts, secrets, collections, and teams. | | Team management | List and create teams, retrieve, update, or delete a team, list and add team members, and list a team's accounts, secrets, and collections. | | Business hub integrations (provisioning) | List Cerby's connected business hub integrations, retrieve one by id, list, retrieve, invite, or remove integration users, list entitlements, update a user's entitlements (replace the set, or add and remove individual entitlements), list integration assets, and list unmatched users. | | Job monitoring | Retrieve an asynchronous job by id to poll automated operations (such as inviting a user or updating an entitlement) until completion. | | Vaults and raw API access | List vaults, plus a flexible "Cerby API request" action that covers every endpoint in the Cerby v1 API. | Anything defined in the [Cerby API](https://developer.cerby.com/) can be accessed through Serval. ## Get your credentials Serval needs a Cerby **workspace API key**. Under Cerby's role-based access control, the key can do exactly what its selected scopes and its creator's workspace role allow. Grant at minimum the four read scopes the connection's health checks exercise - **Read vaults**, **Read users**, **Read items**, and **Read integrations**. Add **Read accounts** if your workflows will read accounts, passwords, or TOTP codes, **Read secrets** for secret reads, and write scopes (for example Write accounts, Write collections, Write secrets, Write integrations) only if your workflows will make changes. Create the key as a user with at least an **Admin** workspace role (Admin, Super Admin, or Owner) - Cerby's teams area requires it, so a key created by a lower-role user fails the teams health check. Cerby's developer documentation is here: [Cerby API documentation](https://developer.cerby.com/). Sign in to Cerby and go to **Settings > Developer > API Keys**. Click **Create API Key** and give it a descriptive name (e.g. "Serval Integration"). Select the scopes your workflows need - at minimum **Read vaults**, **Read users**, **Read items**, and **Read integrations**. Cerby shows the generated key only once. Copy it before closing the page - if it's lost, you must create a new key. It's the subdomain of your Cerby URL: for [https://acme.cerby.com](https://acme.cerby.com) the workspace name is "acme". The API key is displayed a single time at creation. Store it securely - Cerby will not show it again. The connection can do exactly what the key's scopes allow, no more. Some areas (like teams) also require the key's owning user to hold an Admin-level workspace role - see the gotchas below. ## Connect in Serval Add a new Cerby connection from your Serval integrations page. The **Workspace name** field is required and described as 'The Cerby workspace slug from your URL (e.g. "acme" for acme.cerby.com).' Enter only the bare slug - lowercase letters, numbers, and hyphens. If the value contains ".cerby.com", a scheme like "https\://", uppercase letters, a leading hyphen, dots, or underscores, the form rejects it with: Lowercase letters, numbers, and hyphens only. Do not include ".cerby.com". Leaving it blank shows "This field is required". The **API Token** field is required and described as "API key generated in the Cerby web app under Settings -> Developer -> API Keys." Paste the full key you copied from Cerby. Leaving it blank shows "This field is required". Serval builds your workspace's Cerby address from the slug. Use the health checks below to confirm Serval can reach the Cerby API with your token. When you edit an existing connection, the workspace name is shown back as the plain slug and the stored token appears masked (bullets plus its last 4 characters) alongside a control to replace it. Leave the masked token as it is to keep your existing stored token; to rotate it, choose to replace it and paste the entire new key. ## Verifying the connection The Cerby connection ships with five health checks. Each one exercises a different permission, so a failure pinpoints exactly which scope (or role) the key is missing. The four list checks append your workspace total when Cerby returns one - for example "Successfully listed users from Cerby (workspace total: 42)." They also run again automatically whenever you save changes to the connection's settings. * **Validate Cerby API connection** - confirms the token can reach the Cerby API by listing vaults (a lightweight read that exercises the Read vaults scope). On success: "Successfully connected to the Cerby API." On failure: "Unable to connect to the Cerby API. Verify the workspace subdomain and that the API token has the Read vaults scope." * **List Cerby users** - confirms the Read users scope by listing a single user. On success: "Successfully listed users from Cerby." On failure: "Unable to list users from Cerby. Verify the API token has the Read users scope." * **List Cerby teams** - confirms the token can read teams. On success: "Successfully listed teams from Cerby." On failure: "Unable to list teams from Cerby. Verify the API token has the Read users scope and that the user has at least an Admin role." * **List Cerby integrations** - confirms the Read integrations scope by listing one connected business hub integration. On success: "Successfully listed integrations from Cerby." On failure: "Unable to list integrations from Cerby. Verify the API token has the Read integrations scope." * **List Cerby collections** - confirms the Read items scope by listing one collection. On success: "Successfully listed collections from Cerby." On failure: "Unable to list collections from Cerby. Verify the API token has the Read items scope." If "List Cerby users" passes but "List Cerby teams" fails, the problem is usually not a scope: Cerby's teams area requires the key's owning user to hold at least an **Admin** workspace role (Admin, Super Admin, or Owner). Recreate the key as a user with that role. ## Gotchas and troubleshooting Enter only the subdomain - "acme" for acme.cerby.com. Values containing ".cerby.com", a scheme like "https\://", uppercase letters, leading hyphens, dots, or underscores are rejected with: Lowercase letters, numbers, and hyphens only. Do not include ".cerby.com". Serval builds the full workspace address from the slug for you, and only ever sends your token to your workspace's own cerby.com subdomain. Cerby's teams area requires the Read users scope plus at least an Admin workspace role (Admin, Super Admin, or Owner). If the "List Cerby teams" health check fails while "List Cerby users" passes, the API key's owning user likely lacks the required workspace role rather than a scope - create the key as an Admin-level user. Retrieving an account's password is only available for accounts stored in an AWS KMS vault - reads against accounts in other vault types fail by design on Cerby's side. Retrieving an account's TOTP code requires the Read accounts scope. Cerby shows the generated key a single time at creation. Copy it immediately and store it securely. If it's lost, create a new key in Cerby, then edit the Serval connection, replace the masked **API Token** value, and paste the new key (leaving the masked value as it is keeps the old, now-dead key stored). *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Cerby integration. # Cisco IQ Source: https://docs.serval.com/sections/integrations/cisco-iq Connect Serval to Cisco IQ so workflows can read your Cisco install base - assets, contracts, lifecycle milestones, security advisories, and field notices - and sync the asset inventory into Serval. ## About Cisco IQ Cisco IQ (iq.cisco.com) is Cisco's AI-powered support and services platform. Its API exposes your account's install base: assets with contract coverage and lifecycle milestones, support contracts, PSIRT security advisories, and field notices, together with which of your assets each advisory or notice affects. The API is read-only - every operation is a read, so nothing in Serval can change data in Cisco IQ. The integration is marked **Beta** in the connect screen, and Cisco's own API is in beta (public preview): Cisco states that endpoint paths, schemas, and authentication may change between releases without backward compatibility. **Authentication:** A long-lived Cisco IQ token - a service account token (recommended) or personal access token - plus your account ID and data storage region. Serval stores the token encrypted and exchanges it server-side for a short-lived access token (about an hour) before calling the API, so workflows never handle either token. **Data sync:** No background sync starts when you connect. Data access is on-demand through workflows, plus one installable ingestion workflow, "Ingest Assets from Cisco IQ", that syncs your Cisco install-base inventory into Serval as assets. ## What the Cisco IQ integration enables | Capability | Description | | - | - | | Cisco IQ API access | Workflows use the "Cisco IQ API request" action to call the Cisco IQ product API - assets (with 51 filter parameters), asset lifecycle milestones, asset relationships, contracts, security advisories, field notices, and the affected-asset views that connect advisories and notices to your inventory. | | Asset ingestion | The installable "Ingest Assets from Cisco IQ" workflow syncs the install-base inventory - hostname, serial number, product, software version, contract coverage, lifecycle milestones, and telemetry status - into Serval as external assets. | | Connection health checks | Four built-in checks confirm the token works and that the account can read assets, contracts, security advisories, and field notices. | Typical workflow questions this answers: which assets are hit by a given PSIRT advisory, which contracts or coverage windows expire in the next quarter, and which hardware reaches end of support this year. ## Get your credentials Serval needs a Cisco IQ **token**, your **account ID**, and the account's **data storage region**. Use a service account rather than a personal token: personal tokens act as a specific person and stop working when that person's access changes. Sign in to [Cisco IQ](https://iq.cisco.com) as an Account Administrator and go to **System Settings**, then **Identity and Access**, then **Add User**. Choose the **Service Account** type. Service accounts are available on customer accounts only - partner accounts must use a personal access token instead (created under your name, then **User Settings**, then **Generate Token**). A **Viewer** role is sufficient - the integration only reads. Resource groups, if you use them, narrow which assets the account can see; what Serval can read is exactly what this account can read. The token is shown once at creation and never again. A service account supports up to five concurrent tokens (manage them under **Manage API Tokens** on the service account), which is what makes zero-downtime rotation possible later. Both are shown in Cisco IQ under **System Settings**, then **Account Details**. The region is US, EMEA, or APJC. ## Connect in Serval Add a new Cisco IQ connection (marked Beta) from your Serval integrations page. The **Instance Name** field is "A name to identify this Cisco IQ connection, such as Production." Both come from **System Settings**, then **Account Details** in Cisco IQ. The region is a dropdown with US, EMEA, and APJC - entering the wrong region routes requests to the wrong data residency zone, and the connection fails. The **API Token** field takes "A Cisco IQ service account token (recommended) or personal access token." All four fields are required - a missing one is rejected with a message such as "Account ID is required" or "API token is required". The credentials are not tested at save time, so run the health checks right after connecting (see below). To rotate the token later, create the replacement token in Cisco IQ first, edit the connection and paste only the new token (updating with the token field left blank keeps the stored one), confirm the health checks pass, and only then revoke the old token in Cisco IQ. Revoking first breaks the connection. ## Verifying the connection The connection ships four health checks that make live calls to Cisco IQ: * **Validate API connection** - exchanges the stored token for an access token and reads the asset inventory. On success: "Successfully connected to Cisco IQ. \[number] assets are visible to this account." On failure: "Unable to connect to Cisco IQ. Verify the API token, the account ID, and the data storage region." * **List contracts** - reads a single support contract. On failure: "Unable to read contracts. Verify the account's role and resource groups in Cisco IQ." * **List security advisories** - reads a single security advisory. On failure: "Unable to read security advisories. Verify the account's role and resource groups in Cisco IQ." * **List field notices** - reads a single field notice. On failure: "Unable to read field notices. Verify the account's role and resource groups in Cisco IQ." Each of the last three can also pass with a "Connected, but..." message when the account simply has none of that record type visible - that is a healthy connection with an empty collection, not a failure. ## Gotchas and troubleshooting Cisco publishes these APIs as beta (public preview) and states that paths, schemas, authentication, and pagination may change between releases without backward compatibility. Serval tracks the API as it evolves, but a Cisco-side change can break the integration until it is updated - which is why the connection is marked Beta. Authentication and authorization are separate in Cisco IQ: a valid token whose account lacks access returns 403, not 401. What the account can see is set by its role (Administrator or Viewer), its resource groups, and Cisco's own entitlement rules. Cisco also notes that permission changes take from a few minutes to almost an hour to propagate - a 403 right after a permissions change may resolve itself. Cisco IQ enforces 10 requests per second and 5,000 per 24 hours per user or service account, and 25 per second and 25,000 per 24 hours per account - all users and integrations in the account share that account-wide budget. Serval's ingestion uses the largest page size (200 assets per request) to stay well inside it, but heavy custom workflows plus other API consumers in the same account can exhaust the shared window, which returns HTTP 429 until it resets. Assets become external assets keyed by their Cisco IQ asset ID (falling back to serial number), named after the asset's hostname, falling back to its serial number. The full Cisco IQ asset record - contract coverage, lifecycle milestones, telemetry status, and the rest - is attached to each asset. Cisco IQ list responses carry a total count that can be null, meaning unknown - not zero. The first health check reports the count only when Cisco IQ provides one, and paging in workflows should stop on a short page rather than on the count. An access token is scoped to exactly one Cisco IQ account. To work across several accounts (or to scope different teams to different resource groups), create one Serval connection per account or per service account - the instance name keeps them distinct. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Cisco IQ integration. # Cisco Meraki Source: https://docs.serval.com/sections/integrations/cisco-meraki Connect Cisco Meraki to Serval with a Dashboard API key so workflows can call the full Meraki Dashboard API and sync wireless access points into Serval as assets. ## About Cisco Meraki Cisco Meraki is a cloud-managed networking platform: organizations, networks, and devices (including wireless access points) are all administered through the Meraki Dashboard. Serval connects to the Meraki Dashboard with a single Dashboard API key - you paste it in once, Serval stores it encrypted and attaches it as a Bearer token to every request a workflow makes. One connection covers every Meraki organization the key's administrator can see; workflows that need a specific organization take its ID as an input. Serval only ever sends the key to one host for this integration: api.meraki.com. **Authentication:** Meraki Dashboard API key - a single key pasted into Serval. There is no OAuth or sign-in flow. **Data sync:** No background sync starts when you connect. Data access is on-demand through workflows, plus one installable ingestion workflow, "Ingest Access Points from Meraki", that syncs an organization's wireless access points into Serval as assets. ## What the Cisco Meraki integration enables | Capability | Description | | - | - | | Full Meraki Dashboard API access | Workflows use the "Meraki API request" action to call any part of the Meraki Dashboard API v1 - 588 endpoints (859 operations) covering organizations, networks, devices, wireless SSIDs, VLANs, clients, and the rest of the Dashboard API, generated from the v1.64.0 spec. | | Wireless access point ingestion | The installable "Ingest Access Points from Meraki" workflow syncs every wireless access point in a Meraki organization's device inventory into Serval as assets, identified by serial number, with the full device record attached. | | Connection health checks | Three built-in checks confirm the API key is valid and can read your organizations, networks, and devices. | Anything defined in the [Meraki Dashboard API](https://developer.cisco.com/meraki/api-v1/) can be accessed through Serval. ## Get your credentials Serval needs a **Meraki Dashboard API key**, generated from a Dashboard administrator's profile. The key carries exactly the Dashboard permissions of the administrator who generates it - there are no scopes to choose - so generate it from an organization-level admin account if Serval should see all of your organizations, networks, and devices. Meraki's official guide is here: [Meraki API authorization guide](https://developer.cisco.com/meraki/api-v1/authorization/). Go to the [Meraki Dashboard](https://dashboard.meraki.com) and log in as the administrator whose access Serval should use. Click your avatar icon in the top-right corner and open **My Profile**. Scroll down to **API access**. Click **Generate new API key**. Copy the key right away and store it securely - then paste it into Serval's **API Key** field. There are no permission checkboxes anywhere in this process: the key can do exactly what the generating administrator can do, no more and no less. A key generated by an admin with limited or network-scoped access is the most common cause of failed health checks later. ## Connect in Serval Add a new Cisco Meraki connection from your Serval integrations page. The **API Key** field is required (marked with an asterisk) and is described as "Your Cisco Meraki API key. You can generate one from your Meraki Dashboard profile settings." Leaving it empty shows "This field is required". Click **Submit**. If installation fails, the form shows "Failed to install integration" (with details appended when available). On success the connection appears as "Cisco Meraki", pointed at api.meraki.com. Serval does not test or format-check the key when you save - a mistyped or revoked key is accepted at save time and only surfaces when the health checks run. Run them right after connecting (see below). After saving, the key is displayed masked - bullet characters plus its last 4 characters. To rotate it later, click **Replace** next to the masked value and paste the complete new key into the "Enter new value" box. Saving an update with the key field untouched or blank keeps your existing stored key. If an update fails, Serval shows "Failed to update integration:" followed by details, "Failed to update configuration", or "Failed to save configuration. Please try again.", depending on which form you used. One connection covers every Meraki organization the key's administrator can see. Workflows that operate on a specific organization - like the access point ingestion workflow - ask for the organization ID as an input. ## Verifying the connection The connection ships three health checks that make live calls to Meraki: * **Validate Meraki API Connection** - confirms the key authenticates and can list your Meraki organizations. On success it reports "Successfully connected to Meraki API. Found \[number] organization(s)." and its result data includes the IDs and names of the first 5 organizations. On failure: "Unable to connect to Meraki API. Please verify your API key is valid and has the necessary permissions." * **List Networks** - lists the networks in the first organization the key can see, to confirm network read permission. Success: "Successfully listed \[number] network(s) in organization "\[name]"". Failure: "Unable to list networks. Please verify your API key has network read permissions." If the key sees no organizations at all, the check still passes with "No organizations found. Cannot test network listing without an organization." * **List Devices** - lists the devices in the first organization the key can see, to confirm device read permission. Success: "Successfully listed \[number] device(s) in organization "\[name]"". Failure: "Unable to list devices. Please verify your API key has device read permissions." With zero organizations it still passes with "No organizations found. Cannot test device listing without an organization." The network and device checks only probe the **first** organization returned. If the checks are green but a workflow fails against a different organization, the key likely has limited access in that organization - a passing check proved read access in one organization, not all of them. ## Gotchas and troubleshooting The key has exactly the Dashboard permissions of the administrator who generated it - there are no scopes to select. The failure messages "Unable to list networks. Please verify your API key has network read permissions." and "Unable to list devices. Please verify your API key has device read permissions." almost always trace back to a key generated by an admin with limited or network-scoped access. Regenerate the key from an organization-level admin account and replace it on the connection. Connecting starts no background sync. Asset sync ships as an installable ingestion workflow, "Ingest Access Points from Meraki": give it the Meraki organization ID to ingest from, and it pages through that organization's device inventory 1000 devices at a time, keeps only wireless access points, and performs a full sync into Serval keyed by each device's serial number. Assets are named after the device's name, falling back to its model, then to "AP" plus the serial number. Devices that are not wireless access points are not ingested by this workflow - other data stays available on demand through your own workflows. The connection is pinned to Meraki's API host, not to one organization, so organization choice happens per workflow. The easiest way to find an organization ID is to run the **Validate Meraki API Connection** health check - its result data includes the IDs and names of the first 5 organizations the key can see. The **List Networks** and **List Devices** checks pick the first organization returned and test only that one. If your key spans many organizations (for example 12), a passing check confirms network and device read access in a single organization - not all of them. Test the workflow against the specific organization it targets. Click **Replace** next to the masked value and paste the full new key. Never re-enter the masked value (the bullets plus the last 4 characters) as if it were the key. Serval's form discards any value shaped like the masked placeholder before submitting, so a re-pasted mask never overwrites your key through the UI - and a blank update also keeps the previously saved key. That protection lives in the form, though: any other non-empty value that actually reaches the backend is stored verbatim as your key, so a masked string submitted outside the UI - for example through a scripted call - would be saved as the literal API key and break the connection. Serval reaches only api.meraki.com, Meraki's default global API endpoint. Regional clusters with different base addresses - Canada, China, India, and US FedRAMP - are not reachable. Contact **[support@serval.com](mailto:support@serval.com)** if your organization is hosted in one of those regions. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Cisco Meraki integration. # ClickUp Source: https://docs.serval.com/sections/integrations/clickup Connect ClickUp to Serval with a Personal API Token so your workflows can manage tasks, spaces, docs, comments, and time tracking on demand. ## About ClickUp ClickUp is a project management and productivity platform that organizes work as a hierarchy of Workspace > Space > Folder > List > Task. Serval connects to ClickUp using a Personal API Token that you generate in your ClickUp settings. Once connected, Serval workflows can work with nearly everything in ClickUp - tasks, comments, time entries, goals, Docs, Chat, and more - acting as the ClickUp user who created the token. Serval only ever sends the token to ClickUp's official API host (api.clickup.com). **Authentication:** Personal API Token (API key) **Data sync:** On demand only. There is no background sync, no data ingestion, and no pre-built workflows - all reads and writes happen when one of your workflows runs. ## What the ClickUp integration enables | Capability | Description | | - | - | | Task automation | List, read, create, update, and delete tasks in a list or across an entire workspace, including custom field values, tags, dependencies, links between tasks, merges, task members, attachments, and time-in-status data. | | Workspace hierarchy management | Read and manage Spaces, Folders, and Lists, plus views and folder, list, and task templates at every level of the hierarchy. | | Comments and checklists | List and create comments on tasks, lists, and views; reply to comments; create and manage task checklists and checklist items. | | Time tracking | Read, create, start, stop, and edit time entries at the workspace level, check the currently running timer, review entry history and tags, and read legacy per-task time data. | | Goals and custom fields | Read and manage team goals and key results, and read custom field definitions at the list, folder, space, and workspace level. | | People, guests, and groups | Read workspace data, members, guests, user groups, custom roles, seats, and plan info; invite, edit, and remove users and guests on Enterprise plans. | | Webhooks | Create, list, update, and delete ClickUp workspace webhooks. These are webhooks ClickUp sends, managed through the API - Serval does not automatically register a receiver for them. | | Docs, Chat, and audit logs | Work with ClickUp Docs (docs and pages), Chat (channels, direct messages, messages, replies, reactions, members, followers), workspace audit logs, and object access permissions. | | Identity check | Look up which ClickUp user the stored token belongs to - a quick way to verify the connection. | Anything defined in the [ClickUp API](https://developer.clickup.com/) can be accessed through Serval. ## Get your credentials Serval needs a ClickUp Personal API Token. The token is generated by a specific ClickUp user account and carries exactly that user's access to workspaces, spaces, folders, lists, and tasks - so choose the account deliberately. See the [ClickUp API documentation](https://developer.clickup.com/) for background. The token authenticates as the user who generated it and never expires. Prefer a dedicated service account that is a member of every workspace your workflows need, rather than a personal employee account, and plan deliberate rotation. Sign in as the account that should own the connection. Click your avatar in the upper-right corner and select **Settings**. In the sidebar, click **Apps** (direct link: [app.clickup.com/settings/apps](https://app.clickup.com/settings/apps)). Under **API Token**, click **Generate** (or **Regenerate** to rotate an existing token). Click **Copy** and keep the token handy - it typically starts with "pk\_". You will paste it into Serval next. ## Connect in Serval **Instance Name** is the display label for this connection (for example, "ClickUp - IT Workspace"). The form doesn't force you to fill it in when you first connect, but give the connection a name anyway - later edits to the connection are rejected if the name is blank - and make it distinct from any other ClickUp connection on the same team. Paste the token from ClickUp into the **Personal API Token** field. It is a password-style field, so the value is hidden as you type. Save to store the credentials. Serval keeps the token encrypted and uses it for every ClickUp request your workflows make. If installation fails, the form shows "Failed to install integration" along with the underlying error. When you edit an existing connection, the saved token appears masked - bullets plus its last 4 characters - and can't be typed into directly. On the connection's settings page, click the pencil icon next to the masked value (the reconnect dialog has a **Replace** button instead) to get an empty "Enter new value" box, then paste the new token. Leaving the masked value untouched - or saving while the replacement box is still empty - keeps your existing stored token. ## Verifying the connection ClickUp connections don't currently include built-in health checks, so you won't see a health-check panel on this connection the way you do for some other integrations. The quickest way to confirm everything works is to run a workflow step that performs the identity check from the capability table above - asking ClickUp which user the stored token belongs to. If it returns the expected user's record, the token is valid and correctly attached. If it fails, the token is invalid, revoked, or was mistyped - regenerate it in ClickUp and update the connection. A successful identity check only proves the token works - it does not prove the token's owner can see the data your workflows need. If the check passes but a workflow gets "not found" errors or empty results, the token's ClickUp account is probably not a member of the workspace, space, folder, or list involved. ## Gotchas and troubleshooting Serval sends your Personal API Token to ClickUp exactly as ClickUp expects for personal tokens, so a 401 is almost always a token problem: it was revoked, regenerated in ClickUp without updating Serval, or pasted with a typo or stray whitespace. Generate a fresh token in ClickUp and replace it in the connection. Access is exactly the token owner's access. Workspaces, spaces, folders, lists, and tasks that user cannot see return "not found" or empty results in workflows. Use a service account that is a member of every workspace your workflows touch. Also remember ClickUp personal tokens never expire, so set your own rotation schedule. You can safely edit the connection without re-entering the token: leaving the masked **Personal API Token** value untouched - or saving while the "Enter new value" box is still empty - preserves the stored token, and pasting a new token (via the pencil icon on the settings page or **Replace** on the reconnect dialog) rotates it. Just make sure **Instance Name** stays filled in: if you clear it and save, the update fails and Serval shows "Failed to update configuration" or "Failed to update integration", depending on which form you used. The integration can only call ClickUp's official API host (api.clickup.com). Requests to any other host are not permitted, so workflows cannot use this connection to reach other ClickUp URLs or third-party services. ClickUp returns list and search results in numbered pages controlled by a page number, not a cursor. Some endpoints indicate when you have reached the last page, but the most reliable pattern is for workflows that need everything to request page after page and stop when a page comes back with zero items (for example, an empty list of tasks). Connecting ClickUp does not add pre-built workflows, background ingestion, or scheduled syncs. The integration is an on-demand connection for workflows you author, covering ClickUp's current API surface including the newer Docs, Chat, audit log, and access-permission areas. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your ClickUp integration. # ConductorOne Source: https://docs.serval.com/sections/integrations/conductorone Connect ConductorOne (C1) to Serval to automate identity governance work - access reviews, entitlements, access requests, and grant/revoke tasks - through the full ConductorOne API. ## About ConductorOne ConductorOne (now branded C1) is an identity governance and access management (IGA) platform for access reviews, entitlements, provisioning, and access requests. The Serval integration connects to your company's ConductorOne tenant using an API key you create in ConductorOne, and gives Serval workflows access to the full ConductorOne API - apps, entitlements, request catalogs, users, policies, grant and revoke tasks, and search. Serval stores your credentials encrypted and only ever sends them to hosts under conductor.one. **Authentication:** OAuth 2.0 client credentials, using a ConductorOne API key (Client ID and Client Secret) plus your tenant domain. Serval exchanges these for access tokens directly against your tenant. **Data sync:** On-demand only. Serval does not import or continuously sync ConductorOne data in the background. Workflows call the ConductorOne API live when they run, and built-in health checks verify the connection. ## What the ConductorOne integration enables | Capability | Description | | - | - | | Full API access from workflows | Workflows use the "ConductorOne API request" action to call any part of the ConductorOne API - 163 endpoints (243 operations) covering apps, app entitlements and entitlement owners, request catalogs, users, policies, grant and revoke tasks, and search across apps, entitlements, users, and tasks. | | Connection health checks | Three built-in checks run against your live tenant to confirm Serval can authenticate and has permission to read users and apps. | | AI-assisted workflow authoring | Serval's AI knows the full ConductorOne API surface, so it can help you build ConductorOne workflows without you needing to look up API details. | Anything defined in the [ConductorOne API](https://www.c1.ai/docs/conductorone-api/api) can be accessed through Serval. ## Get your credentials You will create one API credential in ConductorOne, which gives you a Client ID and a Client Secret. Together with your Tenant Domain, these are the three values Serval needs. ConductorOne's own guide is here: [how to authenticate API requests](https://www.c1.ai/docs/conductorone-api/authenticate). In the ConductorOne web app, click your username at the bottom of the screen and select **AI & API**. In the **API credentials** section, click **Create credential**. Give it a descriptive name (for example, "Serval Integration"), set the key's lifespan (30 days, 90 days, or never expires), optionally restrict the source IPs in the **Allowed IPs** field, and select the scope of permissions. Choose **Full Permissions**, or select specific roles to limit what the key can do. Click **Create**, then copy the **Client ID** and the **Client Secret**. Your Tenant Domain is the hostname inside your Client ID. The Client ID follows the format random-id\@hostname/use-case - for example, for [strange-hydra-68836@acme.conductor.one](mailto:strange-hydra-68836@acme.conductor.one)/pcc, the Tenant Domain is acme.conductor.one. The Client Secret is shown only once, at creation. Copy it before leaving the page. If you lose it, you will need to create a new credential. If you set a lifespan on the key (30 or 90 days), set a reminder to rotate it before it expires - an expired key makes every Serval health check fail. ## Connect in Serval Add a new **ConductorOne** connection from your Serval integrations page. **Tenant Domain** (required). Enter the full hostname, matching the field's placeholder your-company.conductor.one. The helper text reads "Your ConductorOne tenant domain (e.g., your-company.conductor.one)". Leaving it blank shows "This field is required". Serval does not check the format here - a wrong value is accepted at save time and only surfaces later as failing health checks, so double-check it against the hostname in your Client ID. **Client ID** (required). Paste the full Client ID exactly as ConductorOne shows it, including everything after the @. Helper text: "Your ConductorOne API Client ID". Leaving it blank shows "This field is required". **Client Secret** (required, hidden as you type). Paste the secret you copied at creation. Helper text: "Your ConductorOne API Client Secret". Click **Submit**. If installation fails, the form shows "Failed to install integration" (with details appended when available). On success the connection appears as "ConductorOne". Serval does not test the credentials when you save, so run the health checks below right after connecting. When you later edit this connection, every save must include all three values in full. **Tenant Domain** and **Client ID** come pre-filled with their saved values - keep them complete and correct. The **Client Secret** appears masked (bullet characters plus its last 4 characters); click **Replace** (or the pencil icon) and paste the complete secret before saving, even if you only meant to change another field - this connection does not keep the previously stored secret when the field is left masked or blank. If an update fails, Serval shows "Failed to update integration:" followed by details, "Failed to update configuration", or "Failed to save configuration. Please try again.", depending on which form you used. ## Verifying the connection The ConductorOne integration runs three health checks against your live tenant: | Health check | What it does | On success | On failure | | - | - | - | - | | Test ConductorOne Connection | Confirms Serval can authenticate with your tenant by making a minimal users request. | "Successfully authenticated with ConductorOne" | "Unable to connect to ConductorOne. Please verify your Client ID and Client Secret are valid." | | List ConductorOne Users | Confirms the key can read users by fetching a small sample (up to 10). | "Successfully listed users from ConductorOne (sample size: \[number])" | "Unable to list users from ConductorOne. Please verify the API credentials have the necessary permissions." | | List ConductorOne Apps | Confirms the key can read apps by fetching a small sample (up to 10). | "Successfully listed apps from ConductorOne (sample size: \[number])" | "Unable to list apps from ConductorOne. Please verify the API credentials have the necessary permissions." | The connection test and the users check call the same part of the API, so the usual partial failure is the first two checks passing while "List ConductorOne Apps" fails. That means your credentials are valid but the API key's scope cannot read apps. Recreate the credential in ConductorOne with a broader scope (for example, Full Permissions) and update the connection in Serval. ## Gotchas and troubleshooting Enter the complete hostname, like your-company.conductor.one - not just your-company, and not a URL starting with https\://. Serval uses the value exactly as you type it and does not validate the format when you save, so a malformed value is accepted silently and then fails every health check. Serval also only attaches your credentials to requests sent to hosts under conductor.one, so a value outside that domain can never work. The reliable way to find the right value: it is the hostname inside your Client ID, between the @ and the /. The ConductorOne API key carries its permissions in the scope you chose when creating it - there is nothing to adjust on the Serval side. If the connection authenticates but cannot list apps (or users), the key's scope lacks read permissions. Create a new credential in ConductorOne with a broader scope (such as Full Permissions) and update the Serval connection with the new values. The edit form pre-fills **Tenant Domain** and **Client ID** with their saved values and shows the **Client Secret** masked, with a **Replace** button (or a pencil icon, depending on where you edit). Before saving any change - even one to a different field - click **Replace** and paste the complete Client Secret into the "Enter new value" box. This connection does not preserve the stored secret when the field is left masked or blank, so saving without re-entering it breaks the connection. Keep Tenant Domain and Client ID complete and correct as well, and re-run the health checks after any edit to confirm the connection still works. ConductorOne displays the Client Secret a single time, at creation. If it was lost, there is no way to view it again - create a new API credential in ConductorOne, then edit the Serval connection, click **Replace** on the Client Secret, and re-enter all three fields with the new values. See ConductorOne's guide to [authenticating API requests](https://www.c1.ai/docs/conductorone-api/authenticate). *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your ConductorOne integration. # Confluence Source: https://docs.serval.com/sections/integrations/confluence Connect your Atlassian Confluence Cloud site to Serval to mirror spaces and pages into the Knowledge Base and let workflows read and write Confluence content. ## About Confluence Confluence is Atlassian's cloud wiki and documentation product. The Serval Confluence integration connects one Atlassian Cloud site per connection - once connected, Serval mirrors your spaces, pages, and folders into its Knowledge Base and lets workflows act on Confluence with the permissions you grant. Only Confluence Cloud (sites ending in **.atlassian.net**) is supported; self-hosted Confluence uses the separate [Confluence Data Center](/sections/integrations/confluence-data-center) integration. **Authentication:** Browser-based OAuth 2.0, with two paths - the built-in **Sign in with Confluence (OAuth)** flow (recommended) or a **bring-your-own Atlassian OAuth 2.0 (3LO) app** owned by your organization. Both paths use the same permission picker, and Serval refreshes tokens automatically. **Data sync:** Confluence is a native knowledge source. Serval mirrors spaces, pages, and folder hierarchy into the [Knowledge Base](/sections/documentation/knowledge-base/overview) in the background, including who-can-see-what permissions so agents only answer from pages the requester is allowed to see. Workflow API requests run on demand. ## What the Confluence integration enables | Capability | Description | | - | - | | **Confluence API requests from workflows** | The **Confluence API request** action lets workflows call any part of the Confluence Cloud REST API on your connected site, limited to the permissions you granted. Available from the Confluence integration directly or through the Atlassian umbrella integration. | | **Knowledge Base sync** | Spaces, pages, and folders are mirrored into Serval's Knowledge Base with folder hierarchy preserved. The default permission preset also syncs user, group, and page-restriction information so agent answers respect each page's visibility. Accepting a [knowledge suggestion](/sections/documentation/suggestions/overview) also creates or updates pages in Confluence. | | **Permission presets at connect time** | Two curated presets - **Knowledge Base** (checked by default; read content, search, and resolve user/group permissions) and **Write Pages** (create and update Confluence pages and folders from workflows) - plus an **All permissions** search over the full Confluence permission catalog. | | **Create Confluence Page workflow** | An installable workflow that creates a new page in Confluence with specified content and metadata (installer approval by default). It ships with the Atlassian umbrella integration rather than the standalone Confluence integration. | | **Built-in health checks** | Three connection checks verify authentication, space access, and page access from the integration page. | Anything defined in the [Confluence REST API](https://developer.atlassian.com/cloud/confluence/rest/v2/intro/) can be accessed through Serval. ## Get your credentials Most teams need nothing from Atlassian ahead of time - the recommended path only asks you to sign in and approve access. Creating credentials is only required if your organization wants to use its own Atlassian OAuth app. No Atlassian-side setup. You'll sign in to Atlassian in your browser and approve the permissions Serval requests. All you need is: * An Atlassian account with access to the Confluence Cloud site you're connecting (and the authority to approve app access for it). * Your site's subdomain - the part before **.atlassian.net** in your Confluence address. Confluence Cloud only. For a self-hosted Data Center site, use the [Confluence Data Center](/sections/integrations/confluence-data-center) integration. Choose this if your organization prefers OAuth to run through an app it owns. You'll create an OAuth 2.0 (3LO) integration in the [Atlassian developer console](https://developer.atlassian.com/console/myapps/): Open the [Atlassian developer console](https://developer.atlassian.com/console/myapps/) and create a new OAuth 2.0 (3LO) integration, or open an existing one. Under **Permissions**, add the **Confluence API** and grant every scope you plan to select in Serval's setup dialog. If a scope you pick in Serval isn't granted here, Atlassian will reject the authorization. Under **Authorization**, paste the **Callback URL** shown in Serval's setup form into the Callback URL field. From the integration's **Settings** page, copy the **Client ID** and the **Secret** (click **Show** to reveal it). You'll paste both into Serval. The callback URL must match **exactly**. Copy it from Serval's form using the Copy button - "Register the exact URL Serval provides - a guessed URL will not match the OAuth flow." ## Connect in Serval Open the Confluence integration in Serval and choose **Sign in with Confluence (OAuth)** - it's marked **Recommended** on the selection screen. Type only your subdomain (placeholder: "your-company") - the **.atlassian.net** suffix is shown in the field and added for you. Letters, numbers, and hyphens only, and it can't start or end with a hyphen. If the site is blank or invalid, the form's validation messages are "Confluence site is required" and "Please enter a valid subdomain (letters, numbers, and hyphens only)". Under **Permission Presets** ("Choose from some common use cases"), the **Knowledge Base** preset is checked by default; add **Write Pages** if workflows should create or update pages. The collapsible **All permissions** section lets you "Search the full Confluence permission list (including any scope from presets)". The footer shows "\[number] Confluence permission(s) will be requested." (or "No permissions selected."). At least one permission is required - the Connect button stays disabled until you select one, and submitting without one shows "Select at least one permission." Serval opens Atlassian's consent screen in your browser. Sign in, make sure the correct site is selected, and approve. The consent screen appears on every connect and reconnect. Offline access is always requested automatically on top of your selections - it's how Serval keeps the connection alive without re-prompting you hourly. You can't (and shouldn't) remove it. When you **reconnect**, the site subdomain is prefilled and the picker pre-checks the permissions currently granted, so you only need to add what's missing. On the selection screen, choose **Use your own Atlassian OAuth app** - "Connect with an OAuth 2.0 (3LO) integration owned by your Atlassian workspace." The form shows a read-only **Callback URL** with a **Copy** button (it reads "Loading callback URL..." while it loads, and you can't submit until it appears - "Callback URL is still loading. Wait a moment and try again."). If it fails to load, use **Retry loading callback URL**. Register this exact URL on your Atlassian app before continuing. * **Display name** (optional) - "A friendly name shown in Serval - you choose this." Placeholder: "My Company Confluence". * **Confluence site** (required) - "The subdomain of the Confluence site you're connecting." Same subdomain rules as the standard path. * **Client ID** (required) - "Found on the Settings page of your OAuth 2.0 (3LO) integration." * **Secret** (required) - a password field (placeholder "ATOA..."). "Click Show next to the secret on your integration's Settings page to reveal it." Same picker as the standard path. Every permission you select here must also be granted on your Atlassian app under Permissions, or Atlassian will reject the authorization. Submit, then complete Atlassian's consent screen. You have 10 minutes to finish before the attempt expires and you must restart. The **Secret** is never prefilled. When you reconnect, Serval restores the Display name, Client ID, Confluence site, and permissions - but you must re-enter the Secret every time. If your team has platform-managed OAuth disabled, Serval skips the selection screen and takes you straight to this form - the bring-your-own path is the only one available. Reconnecting an existing bring-your-own connection also opens this form directly. ## Verifying the connection After connecting, run the integration's health checks from the integration page: * **Test Confluence Connection** - confirms Serval can reach your site and authenticate by fetching a small sample of spaces. * Success: "Successfully connected to Confluence" * Failure: "Unable to connect to Confluence. Please verify your API credentials and permissions are correct." * **List Confluence Spaces** - confirms the connection can list spaces. * Success: "Successfully listed spaces from Confluence (sample size: \[number])" * Failure: "Unable to list spaces from Confluence. Please verify your API credentials have permission to view spaces." * **List Confluence Pages** - confirms the connection can list current pages. * Success: "Successfully listed pages in Confluence (sample: \[number])" * Failure: "Unable to search content in Confluence. Please verify your API credentials have permission to search and read content." All three checks only need read access to spaces and pages - they can pass even if the connection is missing the user, group, and restriction permissions that Knowledge Base sync uses to resolve page visibility. If health checks are green but synced answers ignore page restrictions or sync seems incomplete, reconnect and make sure the full **Knowledge Base** preset is checked. ## Gotchas and troubleshooting Serval matches the site you authorized in Atlassian against the subdomain you entered (your input is matched case-insensitively). If they don't match, the connection fails with "target Confluence site '\[subdomain].atlassian.net' not found in accessible resources. Please ensure you have access to this site and selected it during authorization". If your Atlassian account has no authorized sites at all, you'll see "no accessible Confluence sites found". And if no subdomain reaches the server, exactly one authorized site is required - otherwise the attempt fails with "multiple Confluence sites found (\[number]). Please specify which site to connect by providing the subdomain". Double-check the subdomain and make sure you select the right site on Atlassian's consent screen. Permissions are baked into the OAuth consent and stored on the connection. To add permissions (for example, enabling **Write Pages** after the fact), reconnect the integration - the picker pre-checks what's already granted so you only add what's missing. Atlassian's consent screen is shown every time by design. The permissions you select in Serval are requested verbatim from your app. If any selected permission isn't granted on the Atlassian OAuth 2.0 (3LO) integration under Permissions, Atlassian rejects the authorization. As the setup form puts it: "Make sure your integration grants at least these scopes under Permissions." Atlassian requires an exact match between the callback URL registered on your app and the one Serval uses. Always copy the value from Serval's form - "Register the exact URL Serval provides - a guessed URL will not match the OAuth flow." If the form ever shows "Server returned an empty callback URL", retry loading it before submitting. Your app details are held securely for only 10 minutes between submitting the Serval form and completing Atlassian's consent screen. Taking longer fails with "Invalid or expired OAuth state" - restart the connect flow and complete the consent promptly. On reconnect, Serval prefills the Display name, Client ID, Confluence site, and permissions - but the Secret field is always blank and required. There is no keep-the-existing-secret option; have the Secret handy (or reveal it again in the Atlassian developer console) before reconnecting. Both connection paths automatically request offline access so Atlassian issues a refresh token; without it, the connection would die when the one-hour access token expires. If a bring-your-own connection ends up without a refresh token, requests fail with "custom Confluence OAuth app access token expired and no refresh token available; reconnect required" - reconnect to fix it. The connect form appends **.atlassian.net** to your subdomain, and all traffic goes through Atlassian's cloud API. For a self-hosted Data Center site, use the [Confluence Data Center](/sections/integrations/confluence-data-center) integration. If your team has platform-managed OAuth disabled, Serval sends you directly to the bring-your-own-app form and the Back button to the selection screen is disabled. That's expected - only the bring-your-own path is available in that configuration. The Confluence API request action requires the request path to begin with a forward slash. If it doesn't, the request fails with 'Confluence API path must start with "/" (e.g. "/wiki/api/v2/..."); got: \[path]'. Have your workflow builder copy the full path exactly as it appears in Atlassian's REST API documentation, including the leading slash - Serval adds the site-specific prefix for your connected site automatically. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Confluence integration. # Confluence Data Center Source: https://docs.serval.com/sections/integrations/confluence-data-center Connect Serval to your self-hosted Confluence Data Center instance with a personal access token to mirror spaces and pages into the Knowledge Base, with page restrictions and space permissions respected. ## About Confluence Data Center The Confluence Data Center integration connects Serval to a Confluence instance you host yourself. It's a separate integration from [Confluence (Cloud)](/sections/integrations/confluence): it talks directly to your own host and authenticates with a personal access token you provide instead of OAuth. Once connected, Serval mirrors your spaces and pages into its [Knowledge Base](/sections/documentation/knowledge-base/overview), and workflows and Catalyst can call your instance's API on demand. The integration is marked **Beta** in the connect UI. If your Confluence lives at yourcompany.atlassian.net, use the [Confluence (Cloud) integration](/sections/integrations/confluence) instead. **Authentication:** Personal access token. You supply your instance's Base URL and a token; Serval stores the token securely server-side and attaches it to every request on your behalf, so workflows never see the raw token. Basic auth (username plus password) isn't supported. **Data sync:** Confluence Data Center is a native knowledge source. Serval mirrors spaces and pages into the Knowledge Base in the background, including who-can-see-what permissions, so agents only answer from pages the requester is allowed to see. Workflow API requests run on demand. ## What the Confluence Data Center integration enables | Capability | Description | | - | - | | Knowledge Base sync | Spaces and pages, with their parent-child hierarchy, are mirrored into Serval's Knowledge Base. Choose which spaces and pages to sync from the integration's **Knowledge** tab. | | Permission-aware answers | Serval syncs each space's permissions and each page's view restrictions, so agent answers respect who can see each page in Confluence. | | Typed API requests | A "Confluence Data Center API request" action covering the Confluence Data Center REST API - content, spaces, space permissions, page restrictions, search (CQL), users, groups, and labels. Workflows and Catalyst can do anything the connected token is permitted to do. | | Connection health checks | Verify your stored Base URL and token, and that the token can read spaces. | ## What syncs * **Spaces** the token's user can view, and the **pages** in them, nested under their parent pages. * **Space permissions**: the users and groups that can view each space. * **Page restrictions**: the users and groups a restricted page (or a restricted ancestor) is limited to. Serval matches Confluence users to Serval users by email. Confluence Data Center returns a user's email only when your instance's email visibility setting allows the token's user to see it. If emails are hidden, Serval can't match those users, and pages limited to them stay hidden from them in Serval. Data Center has no folders, so the tree is spaces and pages only. ## Get your credentials Personal access tokens are built into Confluence Data Center 7.9 and later. Atlassian's guide is [Using Personal Access Tokens](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html). Serval sees exactly what the token's user can see. Create the token from an account that can view every space you want to sync, for example a dedicated Serval service account. In Confluence, select your profile picture at the top right of the screen, then select **Settings**. Select **Personal Access Tokens** in the left-hand menu. Select **Create token** and give it a name. You can optionally set an expiry - if you do, plan to rotate the token in Serval before it expires. Copy the token immediately - Confluence shows it only once. ## Connect in Serval In Serval, open your team's integrations page and select **Confluence Data Center**. The integration is marked **Beta**. Enter the address you open Confluence at, including its context path if it has one - for example [https://wiki.example.com](https://wiki.example.com) or [https://example.com/confluence](https://example.com/confluence). The URL must start with https\://. Serval removes the https\:// prefix, a trailing slash, and anything after a ? or #, and keeps a port and the context path (entering [https://Example.com:8443/confluence/](https://Example.com:8443/confluence/) stores example.com:8443/confluence). An empty value is rejected with "Base URL is required", an http\:// address is rejected because Serval only connects over HTTPS, and a value Serval cannot read as a host and path is rejected. Paste the token you created into the password field. Serval rejects an empty value. Submit the form. Serval saves the connection and automatically runs the connection health checks. Open the integration's **Knowledge** tab, choose the spaces and pages to include, and start a sync. When editing an existing connection, the Base URL field comes pre-filled with the stored address, and the token field shows a masked placeholder. Leaving the token untouched or blank keeps the stored token, and leaving Base URL blank keeps the stored address - you only need to fill in the field you are changing. ## Verifying the connection * **Validate Confluence Data Center API Connection** - confirms Serval can reach your instance at the stored Base URL and sign in with the stored token by looking up the token's user. * Success: "Successfully connected to Confluence Data Center as \[name]." * Failure: "Unable to connect to Confluence Data Center. Please verify your base URL and personal access token are correct." * **List Confluence Data Center Spaces** - confirms the token can read spaces by listing up to five. * Success: "Successfully listed \[number] Confluence spaces." * If the token's user can't see any space, the check still passes but tells you to grant it View permission on the spaces you want to sync. ## Gotchas and troubleshooting This integration is for self-hosted Confluence Data Center. If your Confluence lives at yourcompany.atlassian.net, use the [Confluence (Cloud) integration](/sections/integrations/confluence) instead. The two aren't interchangeable. Serval always connects to your configured address over HTTPS, so the instance must serve TLS - one that only speaks plain HTTP will not work. Serval also blocks requests to hosts that resolve to internal or private IP addresses, so an instance reachable only on a private network cannot be connected and the health checks will fail even with a valid token. Expose the instance on a publicly resolvable HTTPS address and allow inbound access from Serval before connecting. If Confluence is served under a path such as /confluence, enter it as part of the Base URL. Leaving it off sends every request to the wrong address, and the health checks fail. Serval only sees what the token's user can see. Give that user View permission on the space, and make sure page restrictions don't exclude it. Serval matches Confluence users to Serval users by email. If your instance hides user emails, Serval can't make that match. Allow the token's user to see email addresses in Confluence's user email visibility setting, then sync again. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Confluence Data Center integration. # Coupa Source: https://docs.serval.com/sections/integrations/coupa Connect Serval to your Coupa business spend management instance so workflows can read and update procurement data on demand. ## About Coupa Coupa is a business spend management platform covering procurement, suppliers, invoices, and purchase orders. The Serval Coupa integration connects to a single Coupa instance and calls the Coupa REST API on demand from workflow steps - there are no background jobs or scheduled imports. **Authentication:** OAuth 2.0 client credentials. You create an OAuth client in your Coupa instance and enter its Instance URL, Client ID, Client Secret, and Scopes in Serval. This is a server-to-server connection - no user signs in, and there is no redirect URL to configure. **Data sync:** On demand only. Serval contacts your Coupa instance when a workflow step runs, exchanging the configured client credentials and scopes for an access token issued by your instance. ## What the Coupa integration enables | Capability | Description | | - | - | | Call any Coupa REST endpoint | A single generic "Coupa API request" action sends authenticated requests to your instance's API, supporting any method, path, query parameters, and request body. There are no prebuilt resource modules - every workflow step goes through this action. | | Read users, suppliers, and purchase orders | List and look up Coupa records such as users, suppliers, and purchase orders, subject to the read scopes granted to your OAuth client. | | Create and update records | Write to Coupa objects, such as updating a user, subject to the scopes granted to your OAuth client. | | Paginate large result sets | Coupa returns list results in pages controlled by a limit and offset; workflows request successive pages until a page comes back smaller than the page size. | Anything defined in the [Coupa Core API](https://docs.coupa.com/en/developer-documentation/the-coupa-core-api/coupa-core-api-overview) can be accessed through Serval. ## Get your credentials Serval authenticates with an OAuth 2.0 / OpenID Connect client that you create in your Coupa instance with the **Client Credentials** grant. Coupa's guides on [OpenID Connect clients](https://compass.coupa.com/en-us/products/product-documentation/integration-technical-documentation/the-coupa-core-api/oauth-2.0-and-oidc/openid-connect-clients) and [setting up an OpenID Connect client](https://docs.coupa.com/en/developer-documentation/the-coupa-core-api/oauth-2.0-and-oidc/set-up-an-openid-connect-client) cover this in full detail. In Coupa, go to **Setup > Oauth2/OpenID Connect Clients**. Click **Create** and set **Grant Type** to **Client Credentials**. Give the client a recognizable name such as "Serval Integration" and complete the required contact fields. Coupa scopes follow the pattern service.object.right - for example core.common.read or core.purchase\_order.read. Select every scope Serval should be able to use; the client creation page lists the available scopes. Save the client, then copy the generated **Identifier** and **Secret**. You will enter these in Serval as the Client ID and Client Secret. Store the secret securely as soon as you see it - Coupa may not show it again after you leave the client details page. Grant the client at least core.user.read, core.supplier.read, and core.purchase\_order.read so Serval's connection checks can pass, plus any additional scopes your workflows need. ## Connect in Serval In Serval, add a new Coupa integration to open the connection form. Your Coupa instance hostname (e.g. acme.coupahost.com or acme.coupacloud.com), matching the form's placeholder "acme.coupahost.com". You can paste the full web address - Serval strips any https\:// or http\:// prefix and trailing slash before saving. Leaving it blank fails with "Instance URL is required". The Identifier generated for your OAuth client in Coupa. Leaving it blank fails with "Client ID is required". The Secret generated for your OAuth client, entered in a password field. Leaving it blank fails with "Client Secret is required". When you reopen the form later, the saved secret appears as a masked value - bullet characters plus its last 4 characters - alongside a **Replace** button. Per the form: "OAuth 2.0 scopes to request. Coupa scopes follow the pattern service.object.right (e.g. core.common.read)." Type or paste scopes - commas or spaces split them into individual entries, so you can paste a whole list at once. The field does not offer autocomplete suggestions. These are the scopes Serval includes when requesting access tokens. Although the field is technically optional, enter at least core.user.read, core.supplier.read, and core.purchase\_order.read so the connection health checks below can pass, plus any other scopes your workflows need. Save to finish connecting. Serval then verifies the connection against your instance. When editing an existing connection, any field you leave blank keeps its stored value - the Instance URL, Client ID, Client Secret, and Scopes are only replaced when you enter something new. To rotate the secret, click **Replace** next to the masked value and enter the complete new secret. ## Verifying the connection Serval runs three health checks against your instance, each requesting a single record to confirm authentication and the matching read scope: * **List Coupa Users** - confirms Serval can authenticate and list users. Requires the core.user.read scope. * Success: "Successfully listed users from Coupa" * Failure: "Unable to list users from Coupa. Please verify your OAuth client is valid and has the 'core.user.read' scope." * **List Coupa Suppliers** - confirms Serval can list supplier records. Requires the core.supplier.read scope. * Success: "Successfully listed suppliers from Coupa" * Failure: "Unable to list suppliers from Coupa. Please verify your OAuth client has the 'core.supplier.read' scope." * **List Coupa Purchase Orders** - confirms Serval can list purchase orders. Requires the core.purchase\_order.read scope. * Success: "Successfully listed purchase orders from Coupa" * Failure: "Unable to list purchase orders from Coupa. Please verify your OAuth client has the 'core.purchase\_order.read' scope." Green health checks only prove the three read scopes above. If a workflow step fails while the checks pass, the most likely cause is that the step touches an object or performs a write the client has no scope for - grant the missing scope on the OAuth client in Coupa and list it in Serval. ## Gotchas and troubleshooting The Scopes field in Serval controls which scopes are requested when tokens are minted, but a scope only works if the OAuth client in Coupa was actually granted it. A scope listed in Serval but missing from the client will not unlock the endpoint - missing read scopes are the most common cause of health check failures. Serval's baseline connectivity check lists users, so the OAuth client effectively needs core.user.read for connection verification to pass - even if your workflows never read users. Serval injects access tokens only into requests bound for a direct subdomain of coupahost.com or coupacloud.com, such as acme.coupahost.com. Requests to any other domain - such as a vanity or custom domain - are not authenticated, so the Instance URL must be the standard Coupa hostname. Serval strips the https\:// or http\:// prefix and any trailing slash before storing the Instance URL. Entering [https://acme.coupahost.com/](https://acme.coupahost.com/) and acme.coupahost.com produces the same stored hostname, which Serval also uses to build the address it requests tokens from. On edit, an empty Client Secret - or the masked bullet value the form submits when you never click Replace - preserves the previously stored secret. Blank Instance URL, Client ID, or Scopes likewise keep their existing values. This is intended behavior, so you can safely update one field without re-entering the others. For anyone building workflows: the "Coupa API request" action automatically prefixes every request with your instance hostname and the API base, so paths should be entered as bare resource names (such as users) without any leading prefix. List responses come back as plain arrays paged with limit and offset - a page shorter than the limit signals the last page. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Coupa integration. # CrowdStrike Source: https://docs.serval.com/sections/integrations/crowdstrike CrowdStrike Falcon is a cloud-native endpoint protection (EDR/XDR) platform - Serval connects to your Falcon tenant with an API client so workflows can query hosts, alerts, and users and call the Falcon API on demand. ## About CrowdStrike CrowdStrike Falcon is a cloud-native endpoint protection (EDR/XDR) platform. Serval connects to your Falcon tenant using an OAuth2 API client - a Client ID and Client Secret you create in the Falcon console - scoped to your CrowdStrike cloud region. Once connected, workflows read from and act on Falcon live: querying hosts, triaging detection alerts, looking up users, and reaching the rest of the Falcon API as needed. **Authentication:** OAuth 2.0 client credentials (a Falcon API client). Serval exchanges your stored Client ID and Client Secret for short-lived access tokens automatically - there is no browser redirect or per-user sign-in, and the same machine credential is used for every workflow run. **Data sync:** on demand only. There is no background sync and no entity ingestion - workflows call the Falcon API live in your selected cloud region when they run. ## What the CrowdStrike integration enables | Capability | Description | | - | - | | Query and resolve hosts | List the device IDs in your tenant, then resolve them into full device details - the foundation for inventory, hygiene, and containment workflows. | | Read detection alerts | Query alerts through the current Falcon Alerts API (the replacement for the deprecated Detects API) to drive triage and incident-response workflows. | | Look up Falcon users | List the user accounts in your connected tenant, for access audits and user-management workflows. | | Generic Falcon API access | Call any Falcon REST endpoint through Serval's CrowdStrike API request action - 906 typed endpoint paths spanning alerts, devices and hosts, incidents, real-time response, custom IOCs, prevention, response, and sensor-update policies, users, and more. Serval injects the access token automatically; your API client must hold the matching Falcon scopes. | Anything defined in the [CrowdStrike API](https://developer.crowdstrike.com/) can be accessed through Serval. ## Get your credentials Serval needs an **OAuth2 API client** created in the CrowdStrike Falcon console, with the API scopes your workflows will use. See CrowdStrike's [OAuth2-based APIs documentation](https://falcon.crowdstrike.com/documentation/page/a2a7fc0e/crowdstrike-oauth2-based-apis) for full details. Use the console for your cloud region: falcon.crowdstrike.com (US-1), falcon.us-2.crowdstrike.com (US-2), falcon.eu-1.crowdstrike.com (EU-1), or falcon.laggar.gcw\.crowdstrike.com (US-GOV-1); US-3 and US-GOV-2 tenants use their region's own Falcon console. Note which one you use - you will select the matching region in Serval. Navigate to **Support and resources > API clients and keys** ([direct link](https://falcon.crowdstrike.com/api-clients-and-keys)). Click **Add new API client** and give it a descriptive name (for example, "Serval Integration") and description. Start with read-only scopes. To pass all of Serval's connection health checks, the client needs at minimum **Hosts: Read**, **Alerts: Read**, **User management: Read**, and **Sensor download: Read**; also grant **Sensor update policies: Read**, which is part of the scope set the integration records by default. Add write scopes only as your workflows require them - see the scope reference below. Click **Add**, then copy the **Client ID** and **Client Secret**. The Client Secret is displayed **only once**, at creation, and cannot be retrieved later. Copy it before closing the dialog - if you lose it, you will need to generate a new secret (or a new client) in the Falcon console. The scopes assigned to this API client in the Falcon console are what actually govern the connection's permissions. If a workflow needs to reach additional Falcon areas later (real-time response, custom IOCs, policies, incidents), grant the matching scopes to this client there. ## Falcon API scopes reference Falcon scopes are granular. The console groups them under human-readable names; error messages and API documentation refer to them by identifier. The scopes most relevant to IT and security automation with Serval: | Falcon console scope | API scope identifiers | What it unlocks | | - | - | - | | Hosts | devices:read, devices:write | Search and resolve hosts and their details (read); network-contain a host or lift containment (write). | | Host groups | host-group:read, host-group:write | View host groups (read); create and modify group membership (write). | | Alerts | alerts:read, alerts:write | List and read detection alerts (read); update alert status, assignment, and comments (write). | | Incidents | incidents:read, incidents:write | View incidents and scores (read); update incident status and ownership (write). | | Prevention policies | prevention-policies:read, prevention-policies:write | View prevention policy configuration and assignments (read); create, modify, and assign policies (write). | | Response policies | response-policies:read, response-policies:write | View response policy configuration (read); create, modify, and assign policies (write). | | Sensor update policies | sensor-update-policies:read, sensor-update-policies:write | Monitor sensor versions and update rings (read); manage rollout policies and schedules (write). | | Sensor download | sensor-installers:read | Read the sensor installer catalog - this is the scope Serval's "Test CrowdStrike Connection" health check exercises. | | Real time response | real-time-response:read, real-time-response:write, real-time-response-admin:write | Start remote sessions and run diagnostic commands on endpoints; admin write adds elevated commands, script execution, and file transfer. | | User management | usermgmt:read, usermgmt:write | List Falcon users and their roles (read); create and modify users and role grants (write). | | IOC management | ioc:read, ioc:write | Review custom indicators of compromise (read); create IOCs to block or monitor artifacts (write). | **Host containment impact:** network containment cuts a host off from everything except the CrowdStrike cloud. Grant the Hosts write scope deliberately, use containment actions carefully in workflows, and keep a documented procedure for lifting containment. ## Connect in Serval In Serval, open the CrowdStrike integration and start a new connection. A name to identify this CrowdStrike instance (e.g., 'Production', 'Corporate'). Required to distinguish between multiple CrowdStrike connections. Leaving it empty shows "This field is required"; a whitespace-only value is rejected with "Instance name is required". A dropdown to select your CrowdStrike cloud region: **US-1 (api.crowdstrike.com)**, **US-2 (api.us-2.crowdstrike.com)**, **US-3 (api.us-3.crowdstrike.com)**, **EU-1 (api.eu-1.crowdstrike.com)**, **US-GOV-1 (api.laggar.gcw\.crowdstrike.com)**, or **US-GOV-2 (api.us-gov-2.crowdstrike.mil)**. If missing, you will see "API domain is required". Your CrowdStrike API Client ID, from the API client you created above. Leaving it empty shows "This field is required". Your CrowdStrike API Client Secret (a password field). Leaving it empty shows "This field is required". Submit the form, then run the health checks below to confirm everything works. The API Domain dropdown defaults to **US-2 (api.us-2.crowdstrike.com)** - not US-1. Verify your region before saving; a wrong region breaks authentication entirely. When editing an existing connection, the Client Secret displays obfuscated (bullets plus its last 4 characters). Leaving it blank or unmodified keeps the stored secret - you only need to fill in the fields you are rotating. ## Verifying the connection The CrowdStrike integration ships four health checks: * **Test CrowdStrike Connection** - verifies Serval can authenticate with your tenant by performing a lightweight read of the sensor installer catalog, which requires the **Sensor download: Read** console scope. Success: "Successfully authenticated with CrowdStrike Falcon". Failure: "Unable to connect to CrowdStrike Falcon. Please verify your Client ID and Client Secret are valid and have the necessary API scopes." * **List CrowdStrike Hosts** - confirms the connection can list a small sample of hosts (up to 10). Success: "Successfully listed hosts from CrowdStrike Falcon (sample size: \[number])". Failure: "Unable to list hosts from CrowdStrike Falcon. Please verify the API credentials have the 'devices:read' scope." * **List CrowdStrike Alerts** - confirms the connection can list a small sample of alerts (up to 10) via the current Alerts API. Success: "Successfully listed alerts from CrowdStrike Falcon (sample size: \[number])". Failure: "Unable to list alerts from CrowdStrike Falcon. Please verify the API credentials have the 'alerts:read' scope." * **List CrowdStrike Users** - confirms the connection can list the users in your tenant. Success: "Successfully listed users from CrowdStrike Falcon (sample size: \[number])". Failure: "Unable to list users from CrowdStrike Falcon. Please verify the API credentials have the 'users:read' scope." All four checks can pass while a workflow still fails with a permission error. The checks only exercise reads under four console scopes (Sensor download, Hosts, Alerts, User management) - if a workflow calls any other Falcon area (real-time response, custom IOCs, policy changes, incidents), grant the matching scopes to the API client in the Falcon console. ## Gotchas and troubleshooting The API Domain dropdown defaults to US-2 (api.us-2.crowdstrike.com), not US-1. Serval requests its access token from the cloud region you select, so the wrong region points authentication at the wrong host and every request fails. Check your Falcon console URL to confirm: falcon.crowdstrike.com is US-1, falcon.us-2.crowdstrike.com is US-2, falcon.eu-1.crowdstrike.com is EU-1, and falcon.laggar.gcw\.crowdstrike.com is US-GOV-1. US-3 (api.us-3.crowdstrike.com) and US-GOV-2 (api.us-gov-2.crowdstrike.mil) are also available; pick the one that matches your tenant's region. Connections created through the Serval UI always record the 4 default scopes: sensor-update-policies:read, hosts:read, alerts:read, users:read. These are the integration's own spellings for the same scopes the reference table and health checks name as devices:read (the **Hosts** console scope) and usermgmt:read (the **User management** console scope) - hosts:read and devices:read refer to one scope, as do users:read and usermgmt:read. Effective permissions are whatever scopes are assigned to the API client in the Falcon console - grant scopes there for any additional areas your workflows call, such as [Real Time Response](https://falcon.crowdstrike.com/documentation/page/d5b78bc0/real-time-response), custom IOCs, policies, or incidents. Health-check failures name scopes by API identifier, which does not always match the console label: 'devices:read' corresponds to the console scope **Hosts: Read**, and 'users:read' corresponds to **User management: Read**. The "Test CrowdStrike Connection" check needs **Sensor download: Read**, even though that scope is not named in its error message. When a check fails, grant the matching console scope from the reference table above rather than searching the console for the literal identifier in the error. After creating an API client or changing its scopes in the Falcon console, allow a few minutes for the change to propagate before re-running Serval's health checks. If a check still fails after granting the right scope, wait briefly and retry before rotating credentials. The connection is uniquely identified by its API domain plus its Instance Name. Two tenants in the same cloud region need distinct Instance Names - reconnecting with the same name and region is treated as an update of the existing connection, not a new one. Use names like "Production" vs "Corporate". CrowdStrike displays the Client Secret a single time when the API client is created, and it cannot be retrieved later. If you lose it, generate a new secret (or a new client) in the Falcon console and update the Serval connection. When editing the connection, the Client Secret is displayed obfuscated (bullets plus the last 4 characters). Submitting the form with blank or unmodified obfuscated values keeps the existing stored credentials - you only need to fill in the fields you are rotating. Falcon's list and query operations return lists of resource IDs, not full records; you resolve details by sending those IDs to the matching "entities" operation. Responses come wrapped in a standard envelope containing the resources plus paging metadata, and pagination is offset-based. Query operations filter with [Falcon Query Language (FQL)](https://falcon.crowdstrike.com/documentation/45/falcon-query-language-fql). Workflow authors building on the generic API action should expect this two-step pattern. Like any Falcon API client, the connection is subject to CrowdStrike's API rate limits - heavy polling or per-resource loops can hit them. Prefer the batch "entities" operations (which accept arrays of IDs) over one call per resource, and reduce polling frequency in scheduled workflows. This integration ships no installable workflows and performs no entity ingestion. Everything runs on demand through the generic API request action against the live Falcon API. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your CrowdStrike integration. # CRXplorer Source: https://docs.serval.com/sections/integrations/crxplorer Scan Chrome extensions for security risks from Serval workflows using your team's CRXplorer account. ## About CRXplorer CRXplorer is a browser extension security analysis platform: it scans Chrome extensions and reports how risky they are to use. The Serval CRXplorer integration connects your team's CRXplorer account so workflows can scan any Chrome extension, by extension ID or Chrome Web Store link, and act on the structured analysis that comes back: overall and per-category risk scores, a clear should-use recommendation, safety guidance, and store listing details. **Authentication:** A CRXplorer API token, pasted once by an admin. Serval stores it encrypted and attaches it to every CRXplorer request automatically. The token is only ever sent to one host for this integration: api.crxplorer.com. **Data sync:** On-demand only. There is no background sync, no webhooks, and no imported data. Serval contacts CRXplorer only when a workflow runs a scan or when the connection health checks run. ## What the CRXplorer integration enables | Capability | Description | | - | - | | Scan an extension by ID or store link | Submit a raw Chrome extension ID or a full Chrome Web Store link and get back a structured security analysis. Scans can optionally include the browser type, hostname, and username, and can force a fresh scan instead of a cached result. | | Risk scoring and analysis | Every scan returns an overall score, an overall risk level, and per-category scores for permissions, content scripts, web accessible resources, content security policy, and externally connectable behavior, each with a written justification. | | Usage recommendation and safety guidance | Each result includes a should-use recommendation with reasoning, a browser impact analysis (what data the extension can collect and how it can interact with the browser), and safety guidelines split into security, privacy, and usage lists. | | Store listing details | Results carry the Chrome Web Store listing: extension name, total users, ratings, reviews, developer email, offered-by, latest version, last updated, size, and privacy policy text. | | Cached or fresh scans with shareable results | Reuse CRXplorer's cached results for speed, or force a fresh scan attributed to a specific hostname and username. Every result includes a shareable link and a downloadable report link. | | Workflow access | Workflow builders run all of the above through the "CRXplorer API request" action. | Anything defined in the CRXplorer API can be accessed through Serval. ## Get your credentials You need an API token from your CRXplorer account. Tokens are created in the CRXplorer web app and are shown only once, so have a safe place ready to paste it. Go to your [CRXplorer account page](https://crxplorer.com/account) and sign in. Click **Create New Token**. Copy the generated API token right away and keep it somewhere safe until you have pasted it into Serval. The token is viewable only once, when it is created. If you close the dialog without copying it, create a new token. ## Connect in Serval In Serval, open the connect form for CRXplorer. The dialog is titled "Configure CRXplorer". Paste the token into the **API Token** field. The field is required (marked with an asterisk) and shows the helper text "Your CRXplorer API token for accessing the browser extension scanning API" underneath. Click **Submit**. If saving fails, you will see "Failed to install integration" or "Failed to save configuration. Please try again." - check the token and retry. Serval does not test the token against CRXplorer when you connect. A mistyped or revoked token will still save successfully, so always run the health checks below right after connecting. When you later reopen the connection settings, the saved token is displayed masked: bullet characters followed by its last 4 characters, with a **Replace** button beside it. You do not need to re-enter the token to save other changes - leaving the masked value alone keeps the saved token. To rotate the token, click **Replace**, paste the complete new token, and save. Success shows "CRXplorer updated"; if it fails, you will see "Failed to update integration". ## Verifying the connection The integration ships four health checks. The first three reuse CRXplorer's cached results where available; the last one runs a real scan each time. * **Test CRXplorer API connectivity** - scans the Google Translate extension using a cached result to confirm your token works. Success: "Successfully connected to CRXplorer API". Failure: "Failed to connect to CRXplorer API: \[error details]". * **Scan Chrome extension by ID** - scans the Adobe Acrobat extension by its ID and reads back the extension name and risk level. Success: "Successfully scanned extension by ID". Failure: "Failed to scan extension: \[error details]". * **Scan extension by Chrome Web Store URL** - scans Google Translate using its full Chrome Web Store link and reads back the extension name and overall score. Success: "Successfully scanned extension by URL". Failure: "Failed to scan extension by URL: \[error details]". * **Force new scan of extension** - triggers a fresh scan of the LastPass extension and reads back the shareable link, the report link, and the should-use recommendation. Success: "Successfully forced new scan". Failure: "Failed to force new scan: \[error details]". If the first three checks pass but "Force new scan of extension" fails, look at your CRXplorer account first. It is the only check that consumes a real scan, so account-side limits can fail it while the cached-result checks stay green. ## Gotchas and troubleshooting Serval accepts whatever token you paste without verifying it against CRXplorer, so a wrong or revoked token only surfaces later, when health checks or workflow scans fail. Run "Test CRXplorer API connectivity" right after connecting, and reconnect with a freshly created token if it fails. The "Force new scan of extension" health check triggers a fresh scan of the LastPass extension on every run, which may count against your CRXplorer account's scan usage. These scans are attributed to hostname "test-workstation" and username "healthcheck-user", so entries like that in your CRXplorer scan logs are expected. CRXplorer's API offers exactly one operation: run a scan. There is no way to list past scans or fetch an old result. If you will need a result later, have your workflow capture the shareable link and the report link from the response at scan time. When you reopen the settings, the stored token appears as bullet characters plus its last 4 characters - the full value is never re-displayed. Use those trailing characters to confirm which token is on file. Saving the form without clicking **Replace** keeps the existing token, and even saving with the replacement field left blank keeps it - only a new non-empty value replaces the stored token. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your CRXplorer integration. # CyberArk EPM Source: https://docs.serval.com/sections/integrations/cyberark-epm Connect Serval to your CyberArk Endpoint Privilege Manager (EPM) SaaS tenant for endpoint visibility and remediation workflows - sets, computers, policies, endpoint events, admin audit, endpoint offboarding, and just-in-time elevation. ## About CyberArk EPM The CyberArk EPM integration connects Serval to your CyberArk Endpoint Privilege Manager SaaS tenant through its REST API. It powers endpoint privilege workflows: listing sets, computers, and policies; searching endpoint events (elevation requests, blocked launches, threat detections); pulling the administrator audit trail; offboarding stale endpoint records; and granting time-boxed just-in-time (JIT) local-admin elevation with a recorded justification. **EPM holds no vaulted secrets.** Unlike CyberArk PAM, there is no credential vault behind this API - the surface is endpoint management and security telemetry only, so there is no path through Serval (or through EPM itself) to any stored credential value. The sensitive write is policy creation: a JIT elevation policy makes a user a local administrator, which is why write workflows default to installer approval. **Authentication:** Username and password for a dedicated EPM service account. Serval signs in against your regional EPM login host, caches the short-lived session token, and attaches it to every proxied request - workflow code never sees the password or the token. **Data sync:** On demand only. There is no background sync of computers, policies, or events - Serval calls your tenant only when a workflow or health check runs. ## What the CyberArk EPM integration enables | Capability | Description | | - | - | | Set and endpoint visibility | List EPM sets and the computers in each set - names, platforms, agent versions, and status. | | Policy visibility | List a set's policies and their activation state before making changes. | | Endpoint event search | Search aggregated endpoint events (elevations, blocks, threat detections) over a recent window. | | Admin audit | Pull the tenant-wide administrator audit trail, including everything Serval itself performs. | | Endpoint offboarding | Delete stale or decommissioned endpoint records from a set. | | JIT elevation | Create a time-boxed policy that makes one user a local administrator on one computer, with auditing and a justification. | ## Prerequisites Before connecting, make sure your tenant meets these requirements: Serval signs in against the regional dispatcher for your tenant. Pick the one that matches where your EPM tenant is hosted: | Region | Login host | | - | - | | United States | `login.epm.cyberark.com` | | Europe | `eu.epm.cyberark.com` | | India | `in.epm.cyberark.com` | | Australia | `au.epm.cyberark.com` | | Canada | `ca.epm.cyberark.com` | | Japan | `jp.epm.cyberark.com` | After sign-in, EPM reports back your tenant's real API host (the `ManagerURL`, e.g. `na111.epm.cyberark.com`); Serval discovers and stores it automatically - you never enter it. Create an EPM user that only Serval uses. This is not just least-privilege hygiene: EPM can invalidate an existing session when the same user signs in again, so an account shared with a person or another tool causes intermittent authentication failures on both sides. One integration connection per API user. Scope the account to the sets Serval should manage. Read workflows need set/computer/policy/event visibility; the offboarding and JIT elevation workflows additionally need endpoint-management and policy-creation rights. ## Connect in Serval In Serval, open your team's integrations page and select **CyberArk EPM**. Pick your tenant's regional login host from the dropdown (see the table above). A wrong region fails at sign-in. Enter the dedicated service account's username and password. Serval stores the password encrypted and uses it only inside the proxy to authenticate. A free-form identifier recorded in EPM's admin audit for every action Serval performs. Defaults to `Serval` - change it only if your audit conventions require a specific value. Submit the form. Serval performs a live sign-in immediately: it validates the credentials, rejects an expired password, and discovers your tenant's API host. Then the health checks run (below). **Session behavior:** EPM session tokens expire on an idle timeout your tenant controls ("Timeout for inactive session" under **Administration > Account Configuration**) - there is no documented default and no refresh endpoint. Serval caches each token for a conservative 4 minutes and signs in again as needed, so the service account authenticates regularly during active workflow use. ## Verifying the connection Four health checks run after you connect: 1. **Test Connection** - signs in and lists sets. Failure usually means the wrong region was selected, the credentials are wrong, the service account's password is expired (reset it in EPM and update the integration), or the account is shared and another sign-in invalidated Serval's session. 2. **List Sets** - confirms the service account can see at least the sets Serval should manage. Zero visible sets means the account has no set access yet. 3. **List Computers** - confirms endpoint-read access on the first visible set. Reports clearly (rather than erroring) if no sets are visible. 4. **List Policies** - confirms policy-read access on the first visible set. If Test Connection fails outright, fix the region and credentials first. If it passes but a later check fails, authentication is fine and the service account is just missing EPM permissions - adjust its set access and roles. ## Installable workflows The integration ships with installable workflows (names indicative): | Workflow | Type | | - | - | | List EPM Sets | Read | | Search EPM Computers | Read | | List EPM Policies | Read | | Search EPM Events | Read | | Get EPM Admin Audit | Read | | Delete EPM Endpoint | Write | | Grant EPM JIT Elevation | Write | Write workflows default to **installer approval**: when a help-desk conversation or automation reaches a write step, the workflow pauses for sign-off from the installing team before the change is made in EPM. ## Gotchas and troubleshooting EPM is an endpoint privilege manager, not a credential vault: nothing in this integration (or in EPM's own API) reads stored credential values. The sensitive operation is instead policy creation - a JIT elevation policy grants local-admin rights - which is why it requires installer approval. EPM can invalidate an existing session when the same user signs in again. If a person or another tool shares Serval's account, each sign-in can kill the other side's session, which shows up as intermittent 401s on both sides. Create one EPM user exclusively for Serval, and one per integration connection. EPM reports an expired password at sign-in (`IsPasswordExpired`), and Serval treats it as a hard failure - connecting and every later sign-in will fail until an EPM admin resets the password and you update the integration's credentials. Serval learns your tenant's real API host (the `ManagerURL`) from the sign-in response and pins it. In the rare case CyberArk moves your tenant to a different host, workflows fail with a clear "reconnect the integration" error - edit and re-save the integration's settings to re-discover the new host. Serval never silently switches hosts. The token lifetime follows your tenant's "Timeout for inactive session" setting (**Administration > Account Configuration**). Serval's 4-minute cache is deliberately conservative so it works under any plausible setting; you do not need to tune anything, but very short tenant timeouts increase sign-in frequency. The policy APIs allow 10 calls per 2 minutes on EPM 25.6.x (30 per minute on 26.x) - avoid tight polling loops over policies. Event and audit searches return at most 1000 records per page; Serval's event workflow additionally caps results at 100 aggregated records per run. The integration works on both EPM generations without any version selection: authentication is identical, and API paths omit the optional version segment so each call binds to your tenant server's own version. All built-in workflows and health checks use only APIs documented on both generations (the classic Computers listing and the Policies/Server family). The modern Endpoints APIs - available only on 26.x tenants migrated to the Central Idira console - are exposed for custom workflows on migrated tenants, and are annotated as such in the API reference. The policy-creation body shape (field names, duration units, accepted policy types) varies between EPM versions. Test Grant EPM JIT Elevation against your tenant - ideally on a test computer - before relying on it in production, and check the created policy in the EPM console matches your expectations. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your CyberArk EPM integration. # CyberArk PAM (Self-Hosted) Source: https://docs.serval.com/sections/integrations/cyberark-pam-self-hosted Connect Serval to your self-hosted CyberArk PAM deployment via the PVWA REST API for privileged-access management workflows - safes, safe membership, vault users, credential rotation, and access-request approvals. ## About CyberArk PAM (Self-Hosted) The CyberArk PAM (Self-Hosted) integration connects Serval to a CyberArk Privileged Access Manager deployment you host yourself, through the Password Vault Web Access (PVWA) REST API. It powers privileged-access management workflows: listing safes and accounts, granting and revoking safe membership for just-in-time (JIT) access, vault user lifecycle actions (disable/offboard), triggering CPM credential rotation, and approving or rejecting dual-control access requests. **Serval never retrieves or stores vaulted secret values.** The curated API surface excludes all credential-retrieval endpoints - workflows can manage who has access to safes and when credentials rotate, but there is no path through Serval to read a vaulted password. **Authentication:** Username and password for a dedicated service account (CyberArk-local or LDAP). Serval exchanges the credentials for a PVWA session token and attaches it to every proxied request - workflow code never sees the password or the token. **Data sync:** On demand only. There is no background sync of safes, accounts, or users - Serval calls your PVWA only when a workflow or health check runs. ## What the CyberArk integration enables | Capability | Description | | - | - | | Safe and account visibility | List safes, safe members, and the accounts stored in safes your service account can see - metadata only, never secret values. | | JIT safe access | Grant and revoke safe membership so privileged access can be provisioned just-in-time and cleaned up automatically. | | Vault user lifecycle | Disable a vault user as part of offboarding or incident response. | | Credential rotation | Trigger CPM-managed password change operations on accounts (CyberArk's CPM performs the rotation; Serval only initiates it). | | Dual-control approvals | List pending access requests and approve or reject them, so request/approve flows can run through Serval. | ## Prerequisites Before connecting, make sure your deployment meets these requirements: Your PVWA must be reachable over HTTPS from Serval's egress IPs. Self-hosted deployments typically need a firewall allowlist rule or reverse-proxy exposure for this - PVWA instances reachable only on a private network cannot be connected. The integration uses the Gen2 REST API, available from PVWA 12.0 onward. Create a dedicated account for Serval, either a CyberArk-local user or an LDAP user. RADIUS and SAML authentication types are not supported - they are interactive and cannot be used by an API client. ### Least-privilege guidance for the service account Grant the service account only what the workflows you install actually need: * **Audit Users** (and safe management rights) if you install the vault user lifecycle workflows. * **Membership on the safes Serval will manage**, with `manageSafeMembers` (for grant/revoke workflows), `listAccounts` (for account listing), and `initiateCPMAccountManagementOperations` (for rotation workflows). * **No "Retrieve accounts" permission anywhere.** Serval's API surface has no credential-retrieval endpoints, but the account should not hold that permission regardless - defense in depth. Where your organization's policy supports it, also enable "user cannot be used interactively"-style restrictions on the account and IP-allowlist it to Serval's egress IPs, so the credential is useless outside the integration. ## Connect in Serval In Serval, open your team's integrations page and select **CyberArk PAM (Self-Hosted)**. Enter your PVWA host, for example `pvwa.acme.com`. You do not need to include `https://` - Serval normalizes the value and always connects over HTTPS. Select **CyberArk** for a CyberArk-local service account or **LDAP** for an LDAP-backed one. This selects which logon endpoint Serval uses. Enter the dedicated service account's username and password. Serval stores the password encrypted and uses it only inside the proxy to authenticate. Submit the form. Serval authenticates and runs the health checks (below). **Session behavior:** Serval authenticates via `POST /PasswordVault/API/Auth/{type}/Logon` with `concurrentSession: true` and caches the session token briefly (about 15 minutes), so the service account must be permitted concurrent sessions. Without concurrent sessions, a Serval logon can terminate another active session for the same account (or vice versa). ## Verifying the connection Four health checks run after you connect: 1. **Test Connection** - authenticates against the PVWA and lists safes. Failure usually means the Base URL is wrong, the PVWA is not reachable from Serval's egress IPs, or the username/password/auth type is incorrect. 2. **List Safes** - confirms the service account can enumerate safes. Failure with a working Test Connection means the account has no safe memberships or lacks list rights. 3. **List Users** - confirms vault user read access. Failure typically means the account lacks the Audit Users permission. 4. **List Accounts** - confirms the account can list accounts in its safes. Failure typically means the account is missing `listAccounts` on the managed safes. If Test Connection fails outright, fix reachability and credentials first. If it passes but a later check fails, the service account authenticates fine and is just missing a CyberArk permission - adjust its vault authorizations or safe memberships. ## Installable workflows The integration ships with installable workflows (names indicative): | Workflow | Type | | - | - | | List Safes | Read | | List Safe Members | Read | | List Accounts | Read | | Grant Safe Access | Write | | Revoke Safe Access | Write | | Disable Vault User | Write | | Rotate Account Credentials | Write | | List Pending Access Requests | Read | | Approve Access Request | Write | | Reject Access Request | Write | Write workflows default to **installer approval**: when a help-desk conversation or automation reaches a write step, the workflow pauses for sign-off from the installing team before the change is made in CyberArk. ## Gotchas and troubleshooting The curated API surface excludes every credential-retrieval endpoint, so no workflow (prebuilt or custom) can fetch a vaulted password through Serval. If a workflow needs to hand a credential to a person, do that inside CyberArk (for example via a dual-control access request that Serval approves), not through Serval. Those auth types are interactive (challenge/response or browser redirect) and cannot be driven by an API client. Use a CyberArk-local or LDAP service account. Serval logs on with `concurrentSession: true` and caches the session token for about 15 minutes. If the account is restricted to a single session, Serval's logon and any other use of the account will terminate each other's sessions. Self-hosted PVWAs usually sit behind a firewall. Add an allowlist rule for Serval's egress IPs or expose the PVWA through a reverse proxy over HTTPS. A PVWA reachable only on a private network fails the Test Connection health check even with valid credentials. CyberArk enforces authorization on the service account you configure. A grant/revoke workflow fails if the account lacks `manageSafeMembers` on the target safe; rotation fails without `initiateCPMAccountManagementOperations`. Grant per-safe permissions for exactly the workflows you install. Rotate Account Credentials marks the account for a CPM-managed change; the CPM performs the rotation on its own schedule. A successful workflow run means the operation was queued, not that the password has already changed. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your CyberArk PAM (Self-Hosted) integration. # CyberArk Privilege Cloud Source: https://docs.serval.com/sections/integrations/cyberark-privilege-cloud Connect Serval to your CyberArk Privilege Cloud (ISPSS) tenant via the Privilege Cloud REST API for privileged-access management workflows - safes, safe membership, credential rotation, and access-request approvals. ## About CyberArk Privilege Cloud The CyberArk Privilege Cloud integration connects Serval to your CyberArk Privilege Cloud tenant - the SaaS PAM on CyberArk's Identity Security Platform Shared Services (ISPSS) - through the Privilege Cloud REST API. It powers privileged-access management workflows: listing safes and accounts, granting and revoking safe membership for just-in-time (JIT) access, triggering CPM credential rotation, and approving or rejecting dual-control access requests. **Serval never retrieves or stores vaulted secret values.** The curated API surface excludes all credential-retrieval endpoints - workflows can manage who has access to safes and when credentials rotate, but there is no path through Serval to read a vaulted password. **Authentication:** Username and password for a dedicated CyberArk Identity service user configured as an OAuth confidential client. Serval exchanges the credentials for a short-lived bearer token (`POST /oauth2/platformtoken`) and attaches it to every proxied request - workflow code never sees the password or the token. **ISPSS tenants only.** Your tenant's API host must be on `*.privilegecloud.cyberark.cloud`. Legacy "Privilege Cloud Standard" tenants on `*.privilegecloud.cyberark.com` authenticate through the vault Logon API instead and are not supported by this integration. **Data sync:** On demand only. There is no background sync of safes or accounts - Serval calls your tenant only when a workflow or health check runs. ## What the Privilege Cloud integration enables | Capability | Description | | - | - | | Safe and account visibility | List safes, safe members, and the accounts stored in safes your service user can see - metadata only, never secret values. | | JIT safe access | Grant and revoke safe membership so privileged access can be provisioned just-in-time and cleaned up automatically. | | Credential rotation | Trigger CPM-managed password change operations on accounts (CyberArk's CPM performs the rotation; Serval only initiates it). | | Dual-control approvals | List pending access requests and approve or reject them, so request/approve flows can run through Serval. | **User and group management is out of scope (v1).** On ISPSS tenants, users, groups, and roles are managed in CyberArk Identity, not through the Privilege Cloud vault API - so user-lifecycle workflows (disable/offboard) are not part of this integration. Manage identities in CyberArk Identity directly or via an Identity-focused integration. ## Prerequisites Before connecting, make sure your tenant meets these requirements: Your tenant must live on `*.privilegecloud.cyberark.cloud` (Shared Services). Legacy Privilege Cloud Standard tenants on `*.cyberark.com` are not supported. In the CyberArk Identity Administration portal, note your Identity tenant's host - it looks like `abc1234.id.cyberark.cloud`. This is the `id.cyberark.cloud` host, **not** the portal subdomain you type into a browser. Create a new Identity user for Serval (for example `svc-serval@acme.cyberark.cloud`) and, in its settings, enable **"Is OAuth confidential client"**. That flag blocks interactive login and exempts the account from MFA so the OAuth client-credentials exchange works. The username becomes the OAuth `client_id` and the password the `client_secret`. Add the service user to a role that grants access to Privilege Cloud (for example, a role with the Privilege Cloud Users right), then give it safe-level permissions for exactly the workflows you plan to install. ### Least-privilege guidance for the service user Grant the service user only what the workflows you install actually need: * **Membership on the safes Serval will manage**, with `manageSafeMembers` (for grant/revoke workflows), `listAccounts` (for account listing), and `initiateCPMAccountManagementOperations` (for rotation workflows). * **Authorizer permissions (`requestsAuthorizationLevel1`)** on safes where Serval should approve or reject dual-control access requests. * **No "Retrieve accounts" permission anywhere.** Serval's API surface has no credential-retrieval endpoints, but the account should not hold that permission regardless - defense in depth. ## Connect in Serval In Serval, open your team's integrations page and select **CyberArk Privilege Cloud**. Enter your tenant's API host, for example `acme.privilegecloud.cyberark.cloud`. You do not need to include `https://` - Serval normalizes the value and always connects over HTTPS. The host must end with `.cyberark.cloud`. Enter your CyberArk Identity tenant host, for example `abc1234.id.cyberark.cloud` (from Identity Administration). This is where Serval sends the OAuth token request. Enter the dedicated service user's username and password. Serval stores the password encrypted and uses it only inside the proxy as the OAuth client credentials. Submit the form. Serval authenticates and runs the health checks (below). **Token behavior:** Serval exchanges the credentials at `POST https://{identityHost}/oauth2/platformtoken` and caches the resulting bearer token for the lifetime the response reports (typically 15 minutes), refreshing shortly before expiry. No refresh token is involved - Serval simply repeats the exchange when needed. ## Verifying the connection Four health checks run after you connect: 1. **Test Connection** - authenticates against CyberArk Identity and lists safes. Failure usually means the Identity tenant host is wrong, the service user is missing **"Is OAuth confidential client"**, or the username/password is incorrect. 2. **List Safes** - confirms the service user can enumerate safes. Failure with a working Test Connection means the account has no safe memberships or lacks list rights. 3. **List Accounts** - confirms the account can list accounts in its safes. Failure typically means the account is missing `listAccounts` on the managed safes. 4. **List Platforms** - confirms the account can read target platforms (needed to discover valid platform IDs for account workflows). If Test Connection fails outright, fix the Identity tenant host and service-user setup first. If it passes but a later check fails, the service user authenticates fine and is just missing a CyberArk permission - adjust its role or safe memberships. ## Installable workflows The integration ships with installable workflows (names indicative): | Workflow | Type | | - | - | | List Safes | Read | | List Safe Members | Read | | List Accounts | Read | | Grant Safe Access | Write | | Revoke Safe Access | Write | | Rotate Account Credentials | Write | | List Pending Access Requests | Read | | Approve Access Request | Write | | Reject Access Request | Write | Write workflows default to **installer approval**: when a help-desk conversation or automation reaches a write step, the workflow pauses for sign-off from the installing team before the change is made in CyberArk. ## Gotchas and troubleshooting The curated API surface excludes every credential-retrieval endpoint, so no workflow (prebuilt or custom) can fetch a vaulted password through Serval. If a workflow needs to hand a credential to a person, do that inside CyberArk (for example via a dual-control access request that Serval approves), not through Serval. Tenants on `*.privilegecloud.cyberark.com` use the vault Logon API rather than Identity OAuth. Serval validates that both configured hosts end with `.cyberark.cloud` and rejects legacy hosts at install time. If you are on a Standard tenant, this integration will not connect. Without **"Is OAuth confidential client"** enabled in CyberArk Identity, the `platformtoken` exchange fails - the account is subject to interactive login policies and MFA that an API client cannot satisfy. Enable the flag on the dedicated service user, not on a human account. The token request goes to your Identity tenant host (`abc1234.id.cyberark.cloud`, shown in Identity Administration). Entering the Privilege Cloud portal hostname or your company's vanity login URL there will make authentication fail even with correct credentials. CyberArk enforces authorization on the service user you configure. A grant/revoke workflow fails if the account lacks `manageSafeMembers` on the target safe; rotation fails without `initiateCPMAccountManagementOperations`. Grant per-safe permissions for exactly the workflows you install. Rotate Account Credentials marks the account for a CPM-managed change; the CPM performs the rotation on its own schedule. A successful workflow run means the operation was queued, not that the password has already changed. Unlike the self-hosted product, ISPSS tenants manage users, groups, and roles in CyberArk Identity - the vault user endpoints are not part of this integration's API surface, and there is no disable-user workflow in v1. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your CyberArk Privilege Cloud integration. # Databricks Source: https://docs.serval.com/sections/integrations/databricks Databricks is a data and AI platform built on Apache Spark - connect a workspace to Serval so workflows can call the Databricks Workspace and Account APIs on demand. ## About Databricks Databricks is a data and AI platform built on Apache Spark. The Serval integration connects to a single Databricks workspace using a service principal's OAuth client credentials (the Databricks machine-to-machine flow). Serval exchanges those credentials for an account-level access token using your selected OAuth scopes (`all-apis` by default), which workflows use to call both the Databricks Workspace APIs (clusters, jobs, Unity Catalog, MLflow, SQL, secrets, and more) and the Databricks Account APIs (workspaces, metastores, networking, budgets, and more). Each connection is registered per workspace - the workspace URL identifies the connection, and the display name defaults to the workspace URL unless you provide an Instance Name. **Authentication:** OAuth 2.0 client credentials (Databricks service principal, machine-to-machine flow) **Data sync:** On-demand only - there is no background sync or entity ingestion. Serval calls Databricks only when a workflow step runs, exchanging your stored credentials for a fresh token on each request. ## What the Databricks integration enables | Capability | Description | | - | - | | Call any Workspace API | Workflows can read and manage everything in the connected workspace - Unity Catalog, MLflow, permissions, clusters, jobs, SQL, secrets, policies, vector search, serving endpoints, DBFS, pipelines, instance pools, repos, and apps - across 380 typed Workspace API endpoints. | | Call any Account API | Workflows can manage account-level resources - workspaces, credentials, metastores and storage credentials, networking, customer-managed keys, log delivery, OAuth app integrations, usage downloads, and budgets - across 51 typed Account API endpoints. | | Manage users and groups (SCIM) | Read and update workspace users and groups, as well as account-level users, groups, and service principals, subject to the service principal's permissions. | | Connection health checks | Two built-in checks verify account-level and workspace-level access separately, so you can tell exactly which access tier is missing. | Anything defined in the [Databricks Workspace API](https://docs.databricks.com/api/workspace/) or [Databricks Account API](https://docs.databricks.com/api/account/) can be accessed through Serval. ## Get your credentials Serval needs four things: your Databricks **Account ID**, the **Workspace URL** of the workspace to connect, and a service principal's **Client ID** and **Client Secret**. You create the service principal and its OAuth secret in the Databricks Account Console - see the official [Databricks OAuth machine-to-machine (M2M) authentication](https://docs.databricks.com/aws/en/dev-tools/auth/oauth-m2m) guide. Use the console for your cloud: [accounts.cloud.databricks.com](https://accounts.cloud.databricks.com) for AWS, accounts.azuredatabricks.net for Azure, or accounts.gcp.databricks.com for GCP. Go to **User management**, open the **Service principals** tab, click **Add service principal**, name it (e.g. "Serval Integration"), and click **Add**. Open the service principal, select the **Secrets** tab, and under **OAuth secrets** click **Generate secret**. Set the lifetime (maximum 730 days). Copy both the **Secret** and the **Client ID** immediately. In the Account Console, go to **Workspaces**, select the target workspace, open the **Permissions** tab, click **Add permissions**, select the service principal, and assign a role (e.g. User or Admin). In the Account Console, click your email in the top-right corner (the user menu). The Account ID is a UUID like xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. The OAuth secret is shown **only once**, at generation time. Copy it before closing the dialog - if you lose it, you'll need to generate a new one. Workspace assignment and account-level access are granted separately in Databricks. The service principal needs **both**: workspace assignment for Workspace API calls, and account-level access for Account API calls. Serval's health checks test each tier independently. ## Connect in Serval Every field except Instance Name is required - leaving a required field blank stops submission with "This field is required". Type the bare account ID - the UUID from the Account Console user menu, matching the placeholder "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx". The field only accepts letters, numbers, and hyphens, so anything URL-shaped (containing dots or slashes) is rejected with "Enter your Account ID, not a workspace URL. The Account ID is found in Account Console > User menu." For example "your-workspace.cloud.databricks.com". You can paste it with or without "https\://" - Serval strips the prefix and any trailing slash on save. This URL also tells Serval which cloud's Account API to use (AWS, Azure, or GCP). The Client ID (Application ID) of your Databricks service principal. The OAuth secret you generated in Account Console under Service principals. The field defaults to `all-apis` and offers the full documented set of [workspace API scopes](https://docs.databricks.com/api/workspace/scopes) and [account API scopes](https://docs.databricks.com/api/account/scopes). If your secret is scoped, remove `all-apis` and select the scopes it grants, such as `unity-catalog`, `sql`, or `jobs`. You can select multiple scopes or enter a newly supported scope. Use `all-apis` on its own; Databricks refuses requests for scopes the secret does not grant. The field is labeled **Instance Name (Optional)** - a friendly name to identify this Databricks workspace, e.g. "Production Workspace". If left blank, the connection is named after the workspace URL. When editing an existing connection, text fields you clear or leave blank keep their stored values - so to rotate the Client Secret, you only need to fill in the new secret. Keep at least one OAuth scope selected. The settings page shows the stored secret masked (bullets with the last 4 characters visible); the Client ID is shown in full. ## Verifying the connection Built-in health checks verify authentication and the access allowed by the selected scopes: * **Authenticate with Databricks**: runs for every scope selection and calls the current-identity endpoint to check the OAuth credentials and workspace access. A revoked or invalid secret fails this check even when the resource checks below are skipped. * **List Databricks Unity Catalog Catalogs**: runs when `unity-catalog` is explicitly selected and checks access to the workspace's catalogs. * **List Databricks Workspaces** - lists the workspaces in your Databricks account via the Account API, verifying that the token exchange works and the service principal has account-level access. On success it reports: "Successfully listed workspaces from Databricks account (count: \[number])". On failure: "Unable to list workspaces from Databricks account. Please verify the service principal has account-level access." * **List Databricks Clusters** - lists the clusters in the connected workspace via the Workspace API, verifying the service principal has workspace-level access. On success it reports: "Successfully listed clusters from Databricks workspace (count: \[number])". On failure: "Unable to list clusters from Databricks workspace. Please verify the service principal has workspace-level access." The workspace-list check runs for `all-apis` or `provisioning`; the cluster-list check runs for `all-apis` or `clusters`. Checks for APIs outside the selected scopes report "Skipped". The pass/fail pattern tells you which grant is missing. If **List Databricks Workspaces** passes but **List Databricks Clusters** fails, the service principal hasn't been assigned to the target workspace (Account Console, Workspaces, Permissions tab). If clusters pass but workspaces fail, the service principal lacks account-level access. ## Gotchas and troubleshooting The connect form only accepts an account ID made of letters, numbers, and hyphens (such as the UUID from the Account Console). A value containing dots or slashes - like a workspace URL - fails validation with "Enter your Account ID, not a workspace URL. The Account ID is found in Account Console > User menu." Find the ID in the Account Console by clicking your email in the top-right corner. Serval requests a single account-level token, but Databricks grants account-level and workspace-level access separately. A service principal can pass one health check and fail the other - use the pattern above to identify the missing grant. Note also that each connection is scoped to one workspace: connect each workspace separately. Serval derives the accounts host from the Workspace URL: Azure workspace URLs route to accounts.azuredatabricks.net, GCP workspace URLs to accounts.gcp.databricks.com, and everything else falls back to accounts.cloud.databricks.com (AWS). An incorrect workspace URL can route the token exchange and Account API calls to the wrong cloud's control plane - double-check the URL if both health checks fail. On save, trailing slashes and the "https\://" or "http\://" prefix are stripped, and the normalized URL becomes the connection's instance ID and its default display name. Changing the Workspace URL when editing the connection changes the connection's identity, not just a setting. The update path keeps the stored value for every field you leave empty - Account ID, Workspace URL, Client ID, Client Secret, and Instance Name - so you only fill in what you're rotating. One caveat for direct API callers: the settings read returns the Client Secret masked (bullets plus the last 4 characters), and any non-empty submitted value is stored verbatim. Never send the masked value back as the new secret, or it will be saved literally and break authentication. The standard Serval form handles this for you. Databricks displays the service principal's OAuth secret a single time at generation, with a maximum lifetime of 730 days. If it's lost or expires, generate a new secret in the Account Console and update the connection's Client Secret field - all other fields can stay blank. If a workflow lists resources, be aware that different Databricks APIs page differently: SCIM user and group lists use startIndex/count and return totalResults, newer lists like clusters and jobs use page\_token with page\_size or limit and return next\_page\_token, and some account lists (like workspaces) return a single unpaginated array. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Databricks integration. # Datadog Source: https://docs.serval.com/sections/integrations/datadog Datadog is an observability and monitoring platform - Serval connects to your Datadog organization with an API key and Application key so workflows can query metrics, logs, monitors, dashboards, and more on demand. ## About Datadog Datadog is an observability and monitoring platform covering metrics, logs, monitors, dashboards, APM, and security monitoring. Serval connects to a Datadog organization using a Datadog API key plus an Application key, both stored as secrets and attached to every request Serval makes on your behalf. You select your Datadog site (US1, US3, US5, EU, AP1, AP2, UK1, GOV, or US2-FED) by entering the matching API domain, and an Instance Name distinguishes multiple Datadog connections on the same team. **Authentication:** Datadog API key + Application key (custom header authentication). Both keys are stored as secrets and injected on every request as the DD-API-KEY and DD-APPLICATION-KEY headers. There is no OAuth flow and no token refresh - the keys are used as-is until you rotate them by editing the connection. **Data sync:** On-demand only. Serval calls the Datadog API when a workflow step runs - there is no background sync, and the integration ships no pre-installed workflows. ## What the Datadog integration enables | Capability | Description | | - | - | | Query metrics and timeseries | List active metrics, read metric metadata, and run timeseries queries. | | Search and aggregate logs | Search log events and manage log configuration such as indexes and pipelines. | | Manage monitors and SLOs | Create, read, update, search, mute, and unmute monitors; read and manage SLO definitions, corrections, and history. | | Manage dashboards, hosts, and events | List and manage dashboards and dashboard lists, mute and unmute hosts, and post or query events. | | Read cases, on-call, and security signals | Access cases, on-call schedules and escalation policies, security monitoring rules and signals (including attaching signals to incidents), RUM, DORA metrics, CI visibility, error tracking, and teams. | | Page Datadog On-Call | Create an On-Call page from a workflow and drive its lifecycle - acknowledge, escalate, and resolve. | | Generic Datadog API access | Call any supported Datadog v1 or v2 endpoint (385 typed paths) with full control over the request. | Anything defined in the [Datadog API](https://docs.datadoghq.com/api/latest/) can be accessed through Serval. ## Get your credentials Serval needs two keys from Datadog: an **API key** (authenticates the connection to your organization) and an **Application key** (authorizes access to data like metrics, logs, and monitors). Both are created in Datadog under Organization Settings - see [Datadog: API and Application Keys](https://docs.datadoghq.com/account_management/api-app-keys/) for the official guide. Log in to your Datadog account. For the US1 site that is [https://app.datadoghq.com](https://app.datadoghq.com); if your organization is on another site, use your site's own app domain. Navigate to **Organization Settings > API Keys**, click **New Key**, name it (e.g. "Serval Integration"), and copy the generated API key. Navigate to **Organization Settings > Application Keys**, click **New Key**, name it (e.g. "Serval App Key"), optionally edit its scopes, and copy the generated application key. Check your Datadog dashboard URL to identify your site, then note the matching API domain: api.datadoghq.com (US1), api.us3.datadoghq.com (US3), api.us5.datadoghq.com (US5), api.datadoghq.eu (EU), api.ap1.datadoghq.com (AP1), api.ap2.datadoghq.com (AP2), api.uk1.datadoghq.com (UK1), api.ddog-gov.com (GOV), or api.us2.ddog-gov.com (US2-FED). The Application key inherits the permissions of the Datadog user who creates it. Create it as a user (or service account) with the permissions your workflows need - if that user's permissions are later reduced, what Serval can access narrows with them. See the [Datadog RBAC permissions list](https://docs.datadoghq.com/account_management/rbac/permissions/) for what each permission grants. Getting the API domain right matters more than anything else on this page. Your keys only exist on your organization's site, so a US3 organization's keys will never work against the US1 domain. ## Connect in Serval All four fields are required. Leaving the API Domain or Instance Name blank stops submission with "This field is required", and a submission missing either key is rejected by Serval with an error stating that the key is required. Enter your Datadog site's API host without https\://, e.g. "api.datadoghq.com". The helper text lists the valid options: "Your Datadog API domain (without https\://). Options: api.datadoghq.com (US1), api.us3.datadoghq.com (US3), api.us5.datadoghq.com (US5), api.datadoghq.eu (EU), api.ap1.datadoghq.com (AP1), api.ap2.datadoghq.com (AP2), api.uk1.datadoghq.com (UK1), api.ddog-gov.com (GOV), api.us2.ddog-gov.com (US2-FED). On-Call paging is routed to the matching On-Call host automatically; this connector does not support paging on UK1, GOV, or US2-FED." Anything else is rejected with "Must be a valid Datadog API domain (e.g., api.datadoghq.com, api.uk1.datadoghq.com, api.us2.ddog-gov.com)". Paste the API key you created. This is a password-type field with the helper text "Your Datadog API key. You can generate one from Organization Settings > API Keys". Paste the Application key you created. This is a password-type field with the helper text "Your Datadog application key. Required for accessing metrics, logs, and other data. Generate from Organization Settings > Application Keys". Give the connection a display name, e.g. "Production". The helper text reads "A name to identify this Datadog instance (e.g., 'Production', 'Engineering'). Required to distinguish between multiple Datadog connections." Click **Submit** to create the connection. Serval stores both keys as secrets and verifies the connection with a health check against your Datadog site. When editing an existing Datadog connection, any field you leave blank keeps its current value - only fields you fill in are overwritten. To rotate just the API key, fill in only that field. For security, existing key values are never displayed in the edit form. ## Verifying the connection When the connection is created, Serval runs a health check that confirms your API key is valid and your Datadog site is reachable. The integration also includes four named health-check workflows you can run at any time: * **Validate Datadog API Connection** - confirms the API key is valid and the API is reachable. This check exercises only the API key, not the Application key. On success: "Successfully authenticated with Datadog API". On failure: "Unable to connect to Datadog API. Please verify your API token is valid and has the necessary permissions." * **Check Datadog Organization Access** - verifies Serval can read your organization details. On success: "Successfully accessed organization: \[organization name]". If the API is reachable but returns no organization data: "Could not retrieve organization information from Datadog". On failure: "Failed to access organization information. Please verify your API token has the necessary permissions." * **Check Datadog Metrics API Access** - counts metrics active in the last hour. On success: "Successfully accessed Metrics API. Found \[number] active metrics." On failure: "Failed to access Metrics API. Please verify your API token has the necessary permissions for metrics access." * **Check Datadog Logs API Access** - counts your log pipelines. On success: "Successfully accessed Logs API. Found \[number] log pipelines." On failure: "Failed to access Logs API. Please verify your API token has the necessary permissions for logs access." A green connection check does not prove the Application key works - the initial health check and "Validate Datadog API Connection" only test the API key. If workflows get permission errors while the connection looks healthy, run the Organization, Metrics, and Logs health checks, which do exercise the Application key. ## Gotchas and troubleshooting The API Domain is a free-text field validated against exactly six api.\* domains - it is not auto-detected. If your Datadog organization is on US3 or US5 but you enter api.datadoghq.com (US1), the form accepts it and the connection saves, but every API call fails authentication because your keys only exist on your organization's site. Check your Datadog dashboard URL (e.g. us3.datadoghq.com) and use the matching API domain. Enter it without https\:// - the form requires the bare host, and Serval also strips any https\:// or http\:// prefix defensively. The install-time health check and the "Validate Datadog API Connection" workflow only verify the API key. Reading metrics, logs, monitors, and most other data also requires a valid Application key. If workflow calls return permission errors (403) while the connection looks healthy, check the Application key - and run the Organization, Metrics, and Logs health-check workflows, which do exercise it. What a Serval workflow can read or write in Datadog is bounded by the role and permissions of the Datadog user who created the Application key. Create the key from a user or service account with the permissions your workflows need, and remember that access narrows if that user's permissions are later reduced. When updating an existing Datadog connection, any field left blank (API Key, Application Key, API Domain, or Instance Name) retains its current value - only non-empty fields are overwritten. To rotate just the API key, fill in only that field. Existing key values are never displayed in the edit form. Newer (v2) Datadog APIs, such as log event search, page through results with a cursor: each response includes a cursor value that must be passed into the next request until none is returned. Older (v1) APIs use offset-based paging instead. Some operations also require a specific request method - log search uses POST, not GET. Mixing these up is a common cause of missing results in workflows. Datadog serves On-Call paging from a regional On-Call host, not from the `api.*` domain you enter. Serval derives that host from your API Domain, so there's nothing extra to configure for paging - the API Domain field stays `api.*`-only on purpose. On-Call paging is available on the US1, US3, US5, EU, AP1, and AP2 sites. It is not available on GOV (Datadog doesn't offer On-Call there), and Serval does not yet page on UK1 or US2-FED; attempting to page from a GOV, UK1, or US2-FED connection fails. The connection's identity is built from the API domain plus the Instance Name, which is what lets you connect multiple Datadog organizations (or multiple key sets) to the same team. Pick a stable, meaningful name like "Production" - it is also the connection's display name. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Datadog integration. # Dayforce Source: https://docs.serval.com/sections/integrations/dayforce Connect Dayforce (formerly Ceridian Dayforce) to Serval so workflows can read and update employee, time, and payroll data on demand through a dedicated web services user. ## About Dayforce Dayforce (formerly Ceridian Dayforce) is a human capital management platform covering HR, payroll, benefits, workforce management, and talent. The Serval integration connects to your Dayforce tenant as a dedicated web services user, so workflows can look up employees, pull time clock and time-away data, read org and payroll metadata, and update employee records - all on demand. The Dayforce integration works against Dayforce's V1 REST API only; SOAP web services are not supported. **Authentication:** A dedicated Dayforce web services user with HTTP Basic authentication. Serval signs every request to your tenant automatically. There is no OAuth flow and no token refresh - the stored password simply has to keep matching Dayforce. (Dayforce also offers a token-based sign-in for its API; Serval does not use it.) **Data sync:** On demand only. There is no background or scheduled sync, no Dayforce data is pulled into Serval entities automatically, and no pre-built workflows are installed with this integration. All reads and writes happen inside workflow runs, and four health checks verify the connection. ## What the Dayforce integration enables | Capability | Description | | - | - | | Dayforce API request action | On-demand reads and writes against your Dayforce tenant from any workflow, with sign-in handled automatically. The action covers a fixed set of nine Dayforce endpoints - the rows below. | | List and look up employees | Search the employee directory with filters for status, org unit, employee number, hire and termination date ranges, and last-updated windows (useful for incremental syncs), or fetch a single employee with expandable detail such as employment statuses, work assignments, contacts, and addresses. | | Update an employee | Change fields on an employee record, with an optional validate-only mode that checks the change without saving anything. Updates apply directly to the live HR record. | | Time clock punches | Pull processed punches grouped into shifts, or raw unprocessed punches, for a given time window or business date, with optional filters for employee, location, position, department, and more. | | Time away from work | Retrieve an employee's time-away records (approved, pending, canceled, denied, or cancel-pending) over a date range. | | Org structure metadata | List departments, jobs, and locations. | | Payroll metadata | List pay groups. | | Connection health checks | Four built-in checks that verify your credentials and the specific Dayforce role features the integration needs. | ## Get your credentials Serval connects to Dayforce as a dedicated web services user (a service account) assigned to a role whose Features grant REST API access. You also need your Dayforce server host and your tenant's client namespace. The feature minimums below match exactly what Serval's health checks verify. For Dayforce's own reference, see the [Dayforce RESTful Web Services Developer Guide](https://help.dayforce.com/r/documents/Dayforce-RESTful-Web-Services-Developer-Guide). You need admin access to create users and roles. Open **People**, then **Profiles**, then **Users** (or search for **Users**) and click **Add**. Create a dedicated service user (for example, serval-integration) with a strong password. It does not need to be tied to a real employee. If your tenant enforces password expiration on regular users, exempt this web services user - otherwise the integration breaks silently when the password rotates. Search for **Roles**, click **Add**, name the role (for example, Serval Integration Role), and open its **Features** tab. Expand **HCM Anywhere**, then **Web Services**, and enable **Read Data**. This is required for any REST access. Also enable: **Employee** (with **XRefCode** enabled), **RESTful Services** then **Configuration** then **Departments**, and **RESTful Services** then **Configuration** then **Pay Groups**. Optionally enable **Employee Punches**, **Employee Raw Punches**, **Employee Time Away From Work**, and **RESTful Services** then **Configuration** then **Jobs** and **Locations** for time and org workflows. Enable **Employee Write Data** only if your workflows will update employee records. Add the role under the user's **Authorizations**/**Roles** and save. The server host is, for example, [www.dayforcehcm.com](http://www.dayforcehcm.com) for production, or an environment-specific pod host such as ustest61.dayforcehcm.com (test) or usconfigr57.dayforcehcm.com (config) for sandboxes. The client namespace is the segment that appears after /Api/ in your tenant's Dayforce web addresses. Only enable the role features your workflows actually need. Dayforce role features are additive, so it is much easier to grant access incrementally than to walk it back later. Keep the web services user exempt from password-expiration policies. With Basic authentication, the password Serval stores must match Dayforce at all times - if it rotates, the connection fails with no other warning. ## Connect in Serval In Serval, add the **Dayforce** integration to open the connect form. All four fields are required. Paste only the bare Dayforce hostname - no https\://, no path, no trailing slash. Use [www.dayforcehcm.com](http://www.dayforcehcm.com) for production, or your test-pod host (for example, ustest61.dayforcehcm.com) for sandboxes. The field accepts exactly one name segment before .dayforce.com or .dayforcehcm.com, so a value with extra dots in front is rejected, while hyphenated pod hosts such as us252-services.dayforcehcm.com pass. If the value does not match, you'll see "Must be a Dayforce host (e.g. [www.dayforcehcm.com](http://www.dayforcehcm.com) or ustest61.dayforcehcm.com)". If you leave the field blank, you'll see "This field is required". Your Dayforce client namespace - the segment that appears after /Api/ in your tenant's REST web addresses (for example, MyCompany). If you leave the field blank, you'll see "This field is required". The dedicated web services user you created. Its role must allow REST API access. If you leave the field blank, you'll see "This field is required". The web services user's password. This field is required too, but the form does not check it inline - if you leave it blank on first connect, the save fails with a general installation error rather than a message under the field. Serval composes your API address from the Server and Client Namespace values and names the connection after it (for example, [www.dayforcehcm.com/Api/MyCompany](http://www.dayforcehcm.com/Api/MyCompany)). When you reopen the connection to edit it, Server, Client Namespace, and Web Services Username show their saved values, and the saved password appears masked (bullets with only the last 4 characters visible) next to a **Replace** button. Leaving the password untouched - or clicking **Replace** and saving with the field still blank - keeps the stored password, so you can safely change one field at a time, for example updating the username without re-entering the password. Server and Client Namespace are stored together as one address: if either is blank when you save, the saved address is kept unchanged, so fill in both to point the connection at a different host or namespace. ## Verifying the connection Dayforce connections run four health checks. Each failure message names the exact Dayforce role feature that is missing. **Test Dayforce Connection** - signs in to your tenant by fetching a single employee record. * Pass: "Successfully connected to the Dayforce REST API and authenticated." * Fail: "Unable to connect to Dayforce. Verify that the server, client namespace, username, and password are correct, and that the Dayforce web services role is enabled." **List Dayforce Employees** - confirms the web services user can read employee records. * Pass: "Successfully retrieved employee records from Dayforce (sample size: \[number])." * Fail: "Unable to list employees from Dayforce. Confirm the web services role has Read Data on HCM Anywhere > Web Services > Employee (with XRefCode enabled)." **List Dayforce Departments** - confirms read access to department metadata. * Pass: "Successfully retrieved \[number] departments from Dayforce." * Fail: "Unable to list departments from Dayforce. Confirm the web services role has Read Data on HCM Anywhere > Web Services > RESTful Services > Configuration > Departments." **List Dayforce Pay Groups** - confirms read access to pay group metadata. * Pass: "Successfully retrieved \[number] pay groups from Dayforce." * Fail: "Unable to list pay groups from Dayforce. Confirm the web services role has Read Data on HCM Anywhere > Web Services > RESTful Services > Configuration > Pay Groups." If Test Dayforce Connection passes but a later check fails, your credentials are fine - the role is just missing that check's specific feature. The failure message spells out the exact feature path to enable in the role's Features tab in Dayforce; enable it and re-run the checks. ## Gotchas and troubleshooting The field accepts only a bare Dayforce hostname: exactly one name segment followed by .dayforce.com or .dayforcehcm.com. No https\://, no path, no trailing slash, and no extra dots in the prefix - foo.bar.dayforcehcm.com is rejected, while hyphenated pod hosts like us252-services.dayforcehcm.com pass. If you pasted a full address from your browser, trim it down to just the hostname. "Unable to connect to Dayforce..." means one of the four form values is wrong, or the web services role is not enabled for the user. Re-check the server host and client namespace (the segment after /Api/ in your tenant's web addresses), confirm the username and password, and make sure the role with HCM Anywhere > Web Services > Read Data is actually assigned to the user. Each check maps to one Dayforce role feature: the employees check needs Employee (with XRefCode enabled), the departments check needs RESTful Services > Configuration > Departments, and the pay groups check needs RESTful Services > Configuration > Pay Groups - all under HCM Anywhere > Web Services. The failure message tells you which one to enable. Basic authentication means the password Serval stores must match Dayforce at all times. If the web services user's password expires or rotates, the connection breaks with no other warning - Test Dayforce Connection starts failing with the credentials message. Exempt the user from password-expiration policies, and when you do rotate deliberately, edit the connection and enter the new password (the other fields can stay as they are). The Dayforce API request action supports exactly nine endpoints: the employee list, single-employee lookup and update, processed punches, raw punches, time away from work, departments, jobs, locations, and pay groups. There is no fallback for calling other Dayforce endpoints, and SOAP web services are not supported. If a workflow needs data outside this set, it cannot fetch it through this integration today. An employee update changes the live HR record as soon as it runs - there is no draft or approval stage on the Dayforce side. Use the update's validate-only mode to check a change without saving anything, and test write workflows against a test or config pod before pointing them at production. Updating employees also requires the Employee Write Data role feature, which the health checks do not cover. Every request must include the employee's reference code, a start date, an end date, and a status. The start date is inclusive but the end date is exclusive - records on the end date itself are not returned. Status is case-sensitive and must be exactly one of APPROVED, PENDING, CANCELED, DENIED, or CANCELPENDING. Raw punch lookups always require both a UTC start and end transaction time. Processed punch lookups need either that UTC window or a business date - but this rule is enforced only when the request runs, so a missing window fails at run time rather than while building the workflow. The location, position, department, job, docket, project, and pay-adjustment reference-code filters on processed punch lookups are case-sensitive. List responses return one page of results plus a link to the next page when more pages exist. Workflows must keep following that link until it is absent to read everything. Most list endpoints accept a page-size option, but not all - the pay groups list takes no options at all. Each connection is named after the API address composed from your entries - the server, then /Api/, then the client namespace (for example, [www.dayforcehcm.com/Api/MyCompany](http://www.dayforcehcm.com/Api/MyCompany)). If you connect both production and a test pod, this name is how you tell them apart in Serval. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Dayforce integration. # Daytona Source: https://docs.serval.com/sections/integrations/daytona Connect Daytona cloud development environments to Serval so workflows can create and control sandboxes, snapshots, volumes, and organization settings through the Daytona API. ## About Daytona Daytona is a cloud development environment platform for creating and managing isolated sandboxes. The Serval integration connects to Daytona Cloud or any self-hosted Daytona server using an API key, and gives your workflows full access to the Daytona API - sandbox lifecycle, in-sandbox file, git, and command operations, snapshots, volumes, and organization administration. Serval stores your API key securely and attaches it to every Daytona request your workflows make. **Authentication:** API key (sent as a Bearer token on every request). **Data sync:** On-demand only. Serval does not sync, ingest, or store any Daytona data in the background, and there are no triggers or inbound webhooks. All data access happens at workflow run time through requests Serval makes on your behalf. ## What the Daytona integration enables | Capability | Description | | - | - | | Sandbox lifecycle | Create, list, start, stop, resize, recover, archive, and delete sandboxes; set labels, backups, visibility, and auto-stop, auto-archive, and auto-delete intervals. | | Files and git inside a sandbox | List, upload, download, move, and search files, set permissions, and run git operations such as clone, commit, push, pull, and branch management. | | Process execution | Run commands inside a sandbox, manage long-lived and terminal sessions, and fetch command logs. | | Computer use and language servers | Drive a sandbox desktop (mouse, keyboard, screenshots, display info) and use language-server features such as completions and symbols. | | Snapshots and volumes | Create, list, activate, and deactivate snapshots, fetch build logs, and manage persistent volumes. | | Organization administration | Manage organizations, users, roles, invitations, quotas, usage, and suspension. | | API keys, regions, and runners | List, create, and delete API keys, and manage regions, runner infrastructure, docker registries, jobs, and object storage access. | | Preview URLs, webhooks, audit, telemetry | Generate sandbox port preview URLs (including signed URLs), manage Daytona's outbound webhook portal, read audit logs, and query sandbox telemetry. | Anything defined in the [Daytona API](https://www.daytona.io/docs/en/tools/api/) can be accessed through Serval. ## Get your credentials You need a Daytona API key. Create one in the Daytona Dashboard with the permissions your workflows will use - see the [Daytona documentation](https://www.daytona.io/docs/) for background. Log in to the Daytona Dashboard and open the [Keys page](https://app.daytona.io/dashboard/keys). Click **Create Key** and enter a descriptive name, such as "Serval Integration". Choose an expiration date that fits your security policy. Select the permissions your workflows will need - for example write access to sandboxes and snapshots, and read access to volumes. Health checks below also read sandboxes, organizations, and key details. Click **Create** and copy the generated API key immediately. Daytona shows the API key only once, at creation. Store it in a password or secret manager before leaving the dashboard - you cannot retrieve it later, and Serval never displays the saved key again either. ## Connect in Serval In Serval, open the Daytona integration and start a new connection. Optionally enter a name to distinguish between different Daytona instances (for example, "Development" or "Production"). If you leave it blank, the connection is simply named "Daytona". Enter your Daytona server URL **including the /api path** - for example [https://app.daytona.io/api](https://app.daytona.io/api) for Daytona Cloud, or your self-hosted instance URL ending in /api. The field is required - leaving it blank shows "This field is required". There is no format check beyond that, so double-check it for typos before saving. Paste the API key you created in the Daytona Dashboard. This is a password field and is marked required, but the form does not actually stop you from saving with it blank - a missing or mistyped key only surfaces later as failing health checks, so double-check the paste before you save. After saving, Serval never displays the key again; the edit form shows only a masked placeholder. Save the connection, then run the health checks below to confirm everything works. When editing an existing Daytona connection, the API Key field shows a masked placeholder - and leaving it untouched does **not** keep your existing key. Before saving any edit (even one that only changes the Instance Name or Server URL), use the replace control on the API Key field to paste the complete key, and confirm the Server URL and Instance Name are filled in exactly as desired. Saving with any field blank, or with the API Key left masked, breaks the connection. ## Verifying the connection The Daytona integration ships four health checks: | Health check | What it verifies | On success | On failure | | - | - | - | - | | Validate Daytona API Connection | Your API key authenticates against the configured server. | "Successfully connected to Daytona API. Authenticated as \[name]." | "Unable to connect to Daytona API. Please verify your API key is valid and your server URL is correct." | | List Sandboxes | The key can read your sandboxes. | "Successfully listed sandboxes. Found \[number] sandbox(es)." | "Unable to list sandboxes. Please verify your API key has sandbox read permissions." | | Verify API Key Details | The key itself is valid and active. | "API key "\[name]" is valid and active." | "Unable to verify API key details. The API key may be invalid or expired." | | List Organizations | The key can read your organizations. | "Successfully listed organizations. Found \[number] organization(s)." | "Unable to list organizations. Please verify your API key has organization read permissions." | If "Validate Daytona API Connection" passes but "List Sandboxes" or "List Organizations" fails, your key is valid but missing a scope. Create a new key in the Daytona Dashboard with the needed read permissions and update the connection, replacing the API Key with the new value and confirming every other field is filled in. ## Gotchas and troubleshooting Updating any field on an existing Daytona connection re-saves the whole form. The stored API key appears as a masked placeholder, and leaving it untouched does not carry the old key over - the connection ends up saved without a working key. Before saving any edit, use the replace control on the API Key field and paste the complete key, and make sure Server URL and Instance Name are filled in exactly as desired. If a connection stops working right after an edit, re-open it, re-enter all three fields, and save again. Serval uses the Server URL exactly as you enter it - it never adds /api for you. Use [https://app.daytona.io/api](https://app.daytona.io/api) for Daytona Cloud, or your self-hosted server address ending in /api. A URL without /api is accepted by the form and only fails later at health-check time. The Server URL field only checks that something was entered - typos and malformed URLs pass the form and surface later as the health-check failure "Unable to connect to Daytona API. Please verify your API key is valid and your server URL is correct." If that check fails, verify the URL first. To support self-hosted servers, Serval does not restrict which host the Server URL can point to. Your API key is sent as a credential to that exact address, so verify the URL carefully before saving - especially when copy-pasting it from chat messages or tickets. Serval derives the connection's internal identity from the Instance Name (or uses a default identity named "Daytona" when blank). Renaming the instance later changes that identity, so workflows or references tied to the old name may need updating. Two Daytona connections on the same team with the same Instance Name (or both left blank) share the same internal identifier, so give each connection a distinct name. Daytona displays a new key a single time at creation. If you lose it, you cannot retrieve it from Daytona or from Serval (which never displays the saved key, only a masked placeholder) - create a new key and update the connection, re-entering all fields. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Daytona integration. # DockerHub Source: https://docs.serval.com/sections/integrations/dockerhub Connect Serval to Docker Hub with a username and Personal Access Token so workflows can browse repositories, inspect image tags, and grant teams repository access. ## About DockerHub The DockerHub integration connects Serval to Docker Hub, the container image registry. Once connected with a Docker Hub username and a Personal Access Token (PAT), Serval can list the repositories in your namespace, read repository details, browse and inspect image tags, and grant a team access to a repository. The username you configure is stored with the connection itself, so Serval always knows which namespace it is working with. Organization management (members, teams, invites) is handled by the separate [DockerHub Organization integration](/sections/integrations/dockerhub-org). **Authentication:** Username + Personal Access Token (PAT). Docker Hub does not accept a raw PAT on API calls, so Serval automatically exchanges your username and PAT for a short-lived access token and refreshes it just before it expires. Your PAT is stored encrypted and is never exposed to workflows. **Data sync:** On-demand only. There is no background sync or data ingestion - Serval calls Docker Hub live whenever a workflow or health check needs it. ## What the DockerHub integration enables | Capability | Description | | - | - | | List repositories in a namespace | Browse the repositories in your connected namespace, with optional filtering by name and sorting by name, last updated, or pull count, in ascending or descending order. Results are paginated (10 per page by default, up to 100). | | Get repository details | Read full repository metadata, including your permission level (read, write, or admin), the full description, collaborator count, and immutable-tags settings. | | List tags for a repository | Page through a repository's image tags, including per-architecture image entries, sizes, digests, and last pulled and pushed timestamps. | | Get a specific tag | Look up a single tag and see its status, full size, digest, and image details. | | Grant a team access to a repository | Give one of your organization's teams read, write, or admin access to a repository. Look the team up through the [DockerHub Organization integration](/sections/integrations/dockerhub-org) first. | These operations follow the official [Docker Hub API](https://docs.docker.com/reference/api/hub/latest/). Endpoints that require an Organization Access Token (members, teams, invites) are deliberately excluded from this integration and live in the [DockerHub Organization integration](/sections/integrations/dockerhub-org). ## Get your credentials You need a Docker Hub Personal Access Token created under the account whose username you will enter in Serval. Ideally this is a dedicated service account added to your organization with the minimum role needed. See the official [Docker Hub personal access tokens](https://docs.docker.com/security/access-tokens/) guide for details. Go to [Docker Hub](https://hub.docker.com), sign in, and select your avatar in the top-right corner. From the avatar drop-down menu select **Account settings**, then select **Personal access tokens**. Select **Generate new token** and give it a recognizable description (for example, "Serval integration - production"). Docker Hub asks for an expiration date and the token's access permissions (Read, Write, or Delete). Read access is enough for browsing repositories and tags; include Write if your workflows will grant teams access to repositories. These three names are the only ones Docker Hub shows at this screen; where scope names like `Public Repo Read`, `Read & Write`, or `Repo:Read` appear elsewhere on this page, choose **Read** to cover the read scopes and add **Write** to cover `Read & Write`. Select **Generate** and copy the token immediately - Docker Hub will not show it again. Docker Hub shows the token only once, at creation. If you navigate away before copying it, you will need to generate a new one. Create the token under a dedicated service account where possible, and grant that account the minimum role it needs in your organization. The token only works for the account that created it, so the username you enter in Serval must match. ## Connect in Serval Find **DockerHub** in Serval's integrations and start a new connection. The DockerHub username that owns the Personal Access Token. This is also the default namespace for repository operations. Leading and trailing spaces are removed automatically. Leaving it blank stops submission with "This field is required"; a value of only spaces is rejected by Serval with an error that includes "Username is required." Paste the token you copied from Docker Hub. The field's helper text notes that it requires at least the `Public Repo Read` scope; use `Read & Write` for full repository management. Submitting without a token is rejected by Serval with an error that includes "Personal Access Token is required." A name to identify this DockerHub connection (for example, "Production" or "Build Bot"). It is required to distinguish between multiple DockerHub connections on the same team and is shown as the connection's display name. Leaving it blank stops submission with "This field is required"; a value of only spaces is rejected by Serval with an error that includes "Instance Name is required to distinguish multiple DockerHub connections." Save, then run the health checks below to confirm everything works. When editing an existing connection, Username and Instance Name come pre-filled and the Personal Access Token appears as an obfuscated value (bullets plus its last 4 characters) with a **Replace** button. Leave the token untouched and the stored value is kept, so you can rename the connection without re-entering the token. Any field that reaches Serval empty keeps its current stored value; if no value can be determined for a required field, the update is rejected with an error that includes "Username, Personal Access Token, and Instance Name are required." ## Verifying the connection When the connection is created, Serval verifies it by listing the repositories in your namespace. The integration also ships three named health checks you can run at any time. **Validate DockerHub API Connection** - confirms your stored credentials can be exchanged for a working access token by listing your namespace's repositories. * Success: Successfully authenticated with DockerHub as "\[username]" (\[number] repositories in namespace). * Failure: Unable to authenticate with DockerHub. Verify the username and Personal Access Token, and confirm the PAT has not been revoked. If the error message mentions `token issued from personal access token is not allowed`, the endpoint being called requires an Organization Access Token (OAT) -- use the `dockerhub-org` integration for those operations. **List DockerHub Repositories** - confirms the token can list repositories in your configured namespace and reports the total count plus up to five repository names. * Success: Successfully listed repositories in the \[username] namespace (\[number] total). * Failure: Unable to list DockerHub repositories. Ensure the Personal Access Token has at least the `Public Repo Read` scope, and that the configured username matches a real DockerHub namespace. **Verify DockerHub Tag Access** - fetches one tag from the first repository in your namespace to confirm the deeper tag-level lookups workflows rely on are reachable. If the namespace has no repositories yet, the check still passes with: Namespace "\[username]" has no repositories yet; tag-access check skipped. * Success: Successfully fetched tag listing for "\[namespace]/\[repository]" (\[number] tags). * Failure: Unable to fetch tag listings. This typically indicates the PAT lacks `Repo:Read` scope, or the repository in the namespace is private and the PAT does not have access to it. If all three checks are green but a workflow step that manages organization members, teams, or invites fails with "token issued from personal access token is not allowed", that is expected: those operations need the [DockerHub Organization integration](/sections/integrations/dockerhub-org), not this one. ## Gotchas and troubleshooting Listing or searching organization members, creating or deleting teams, adding or removing team members, and managing invites all require an Organization Access Token and fail here with "token issued from personal access token is not allowed". Use the [DockerHub Organization integration](/sections/integrations/dockerhub-org) for those operations. Docker Hub does not accept a raw PAT for API calls, so Serval automatically exchanges your username and token for a short-lived access token behind the scenes - you never need to manage tokens yourself. If you still see this error, the operation either requires an Organization Access Token (see above) or is using an older, deprecated style of Docker Hub endpoint that no longer accepts PAT-based access. The one deliberate exception on the older endpoint style is granting a team access to a repository, which still works with a PAT and is supported by this integration. On the edit form, the Personal Access Token is shown obfuscated with a **Replace** button, and any field that reaches Serval empty keeps its stored value. This means you can safely change just the Instance Name without re-entering the token. To rotate the PAT, click **Replace** and paste the full new token. The Verify DockerHub Tag Access check reports success when the namespace has no repositories ("...has no repositories yet; tag-access check skipped."). Until at least one repository exists in the namespace, a green result there does not confirm tag-level access. Neither operation is part of the API surface this integration supports. An earlier version of this page listed both as features; they are not supported. This integration only talks to Docker Hub's management interface at hub.docker.com. Actually pulling or pushing container images uses a different system with its own authentication and is not part of this integration. Docker Hub lets you set an expiration date when you create a token, and SSO-enabled organizations cannot rotate PATs through the API as of this writing - rotation is done manually in the Docker Hub UI. Set a rotation schedule, generate the new token in Docker Hub, then edit the Serval connection, click **Replace** on the token field, and paste the new token. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your DockerHub integration. # DockerHub Organization Source: https://docs.serval.com/sections/integrations/dockerhub-org Connect Serval to a Docker Hub organization with an Organization Access Token to automate member, invite, and team management. ## About DockerHub Organization The DockerHub Organization integration connects Serval to a Docker Hub organization using an Organization Access Token (OAT). It covers the organization-administration side of Docker Hub: listing and searching members, changing member roles, removing members, viewing pending invites, and creating and managing teams (Docker Hub calls them groups). Repository-level work - image tags, repository descriptions, and granting teams access to repositories - lives on the sibling [DockerHub integration](/sections/integrations/dockerhub) instead. Serval talks to a single host for this integration: hub.docker.com. **Authentication:** Organization Access Token (OAT). Serval stores the token encrypted and exchanges it behind the scenes for a short-lived session credential when workflows make requests, caching and refreshing that credential automatically - your workflows never see the raw token. **Data sync:** On-demand only. Nothing is imported or polled in the background; Serval calls Docker Hub at the moment a workflow runs an action. ## What the DockerHub Organization integration enables | Capability | Description | | - | - | | List and search organization members | Browse the member roster, filter it, and look up a specific member - including resolving a person by their email address. | | Update a member's role | Change a member's organization role to owner, editor, or member. | | Remove a member | Take a member out of the organization. | | List pending invites | See invitations that have been sent but not yet accepted. | | List teams (groups) | Browse the organization's teams, with search and filtering. | | Create a team | Add a new team with a name and optional description. | | Get, update, or delete a team | Read a team's details (including the numeric team id needed for repository grants on the sibling DockerHub integration), rename it, edit its description, or delete it. | | List team members | See who belongs to a given team. | | Add a member to a team | Place an existing organization member onto a team. | | Remove a member from a team | Take a member off a team. | These capabilities map to the organization-management surface of the [Docker Hub API](https://docs.docker.com/reference/api/hub/latest/). Repository-level endpoints are deliberately left to the sibling [DockerHub integration](/sections/integrations/dockerhub). ## Get your credentials You need two things: your organization's exact name (slug) on Docker Hub, and an Organization Access Token (OAT) issued for that organization. An OAT is an opaque secret starting with `dckr_oat_` that carries organization-admin scopes such as Member Read and Group Read. See [Docker's organization access tokens documentation](https://docs.docker.com/enterprise/security/access-tokens/) for full details. An OAT is a different credential class from a Personal Access Token. You cannot create one in Docker Hub under **Account Settings > Personal access tokens**, and a Personal Access Token will not work with this integration. If you only have a Personal Access Token, use the sibling [DockerHub integration](/sections/integrations/dockerhub) for repository operations instead. OATs are created in the Docker Admin Console by an organization owner. Docker requires a Docker Team or Business subscription: Team plans allow up to 10 OATs per organization, Business plans up to 100. Sign in to Docker Home, select your organization, then select **Admin Console**, then **Access tokens**. Select **Generate access token**, then give the token a label, an optional description, and an expiration date. Under the organization permissions, grant the scopes that cover the operations your workflows will use: **Member Read** and **Member Edit** for listing members and changing or removing them, **Invite Read** for pending invites, and **Group Read** and **Group Edit** for team management. This integration only uses the organization permissions; repository permissions (Image Pull and Image Push) can be left unset. Record the exact organization slug - the segment that follows hub.docker.com/u/ in your organization's Docker Hub page address. You will enter it as the Organization Name in Serval. Copy the token somewhere safe as soon as it is issued. You will paste it into Serval in the next section. ## Connect in Serval In Serval, add a new DockerHub Organization connection. Type your Docker Hub organization slug into the field with placeholder "your-dockerhub-org". Extra spaces are trimmed automatically. Leaving it empty fails with: "Organization Name is required." Paste the `dckr_oat_` token into the password field. Leaving it empty when first connecting fails with: "Organization Access Token is required." Give the connection a friendly label such as "Production" or "Engineering" so you can tell multiple connections apart. Leaving it empty fails with: "Instance Name is required to distinguish multiple DockerHub Organization connections." Serval stores the token encrypted. When you revisit the form later, the token is shown obfuscated as bullet characters plus its last 4 characters. When editing a saved connection, any field you leave blank keeps its previously saved value - including the token, so submitting the form with the obfuscated token still in place does not wipe your credential. To rotate the token, paste the new one over it and save. If an update would leave any field empty, it is rejected with: "Organization Name, Organization Access Token, and Instance Name are required." ## Verifying the connection The integration ships three health checks that run against your real organization: **Validate DockerHub OAT Connection** - confirms the token authenticates and has organization-admin access by fetching a single member of the configured organization. * Success: "Successfully authenticated against DockerHub organization "\[name]" (\[number] members visible)." * Failure: "Unable to authenticate against the DockerHub organization. Verify the Organization Access Token has not been revoked, that the Organization Name matches a DockerHub org the OAT was issued for, and that the OAT has org-admin scope." **Search DockerHub Organization Members** - fetches a small sample of the member list, confirming access to the same listing-and-search endpoint real workflows use when resolving a person by email. * Success: "Successfully fetched member listing for "\[name]" (\[number] members; showing first \[number])." * Failure: "Unable to list members of the DockerHub organization. Confirm the Organization Access Token has organization-admin scope." **List DockerHub Organization Groups** - confirms the token can list the organization's teams. * Success: "Successfully listed organization groups (\[number] total in "\[name]")." * Failure: "Unable to list groups in the DockerHub organization. Confirm the Organization Access Token has organization-admin scope." If all three checks are green but a workflow still fails when granting a team access to a repository, that is expected: repository grants live on the sibling [DockerHub integration](/sections/integrations/dockerhub), which uses a Personal Access Token. Look up the team here, then perform the grant there. ## Gotchas and troubleshooting Docker Hub rejects Personal Access Tokens on every organization, member, and team operation this integration uses, with the message "token issued from personal access token is not allowed". If you only have a Personal Access Token, use the sibling [DockerHub integration](/sections/integrations/dockerhub) for repository operations. This integration requires an Organization Access Token. The Organization Name does double duty: Serval uses it both to address your organization and to exchange the token for a session credential. A wrong or misspelled Organization Name breaks that exchange even when the token itself is fine. Verify the name exactly matches the organization the token was issued for - it is the slug from your organization's Docker Hub page address. Docker Hub will not auto-invite someone who is not already in the organization. Resolve the person first with the member search (for example by email) and confirm they are an organization member before adding them to a team. For workflow builders: the add-to-team operation expects the person's username in a field named "member", not "username". Docker Hub intentionally keeps repository team-grants callable with a Personal Access Token, so that capability lives on the sibling [DockerHub integration](/sections/integrations/dockerhub). The two-step flow: look up the team here to get its numeric team id, then perform the grant on the DockerHub integration using that id and the desired permission level. A single workflow can use both connections together. If you build your own requests with the "DockerHub Organization API request" action, do not add a trailing slash to organization paths - Docker Hub returns a not-found error if you do. Docker Hub also has no endpoint that fetches the organization by itself; to verify an organization name and token scope, list one member or one team instead (exactly what the health checks do). When you edit a saved connection, the stored token is shown obfuscated, and any field left blank - including the token - keeps its previously saved value. Submitting the form without touching the token does not clear the credential. To rotate the token, paste the new one into the Organization Access Token field and save. List operations return results in pages, with a count and links to the next and previous pages. The default page size is 10 and the maximum is 100, so a workflow that needs every member or team of a large organization should page through the results. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your DockerHub Organization integration. # Docusign Source: https://docs.serval.com/sections/integrations/docusign Connect your own Docusign OAuth app to Serval so workflows can send, track, and manage e-signature envelopes on demand. ## About Docusign Docusign is an electronic signature and agreement management platform. Serval connects to a single Docusign account using a Docusign app that you create and own - you paste your app's Integration Key and Secret Key into the connect modal, approve access on Docusign's consent screen, and Serval binds the connection to your default Docusign account. Workflows can then read and write Docusign data on demand. **Authentication:** OAuth 2.0 Authorization Code grant with a customer-supplied (bring-your-own) Docusign app, against either the Production or Demo environment. **Data sync:** On-demand only. There is no background sync, no webhooks, and no entity ingestion - Docusign is contacted only when a workflow step runs the "Docusign API request" action. ## What the Docusign integration enables | Capability | Description | | - | - | | Read account information | Look up the connected account's name, billing plan, suspension status, and (optionally) full account settings. | | List envelopes | Find envelopes by date range, status, sender email, or folder, with sorting and paged results - keep paging until no next page is reported. | | Create and send envelopes | Send documents for signature with signers and carbon-copy recipients in a routing order, or send from a saved template; send immediately or save as a draft. | | Read and update an envelope | Check an envelope's status, subject, and timestamps, update it, or re-send it to recipients. | | Read envelope recipients | See signers and carbon copies, their routing order, and optionally their signing fields and extended details. | | List and search templates | Browse and search templates by text or folder to drive template-based sends. | All of this runs through a single typed workflow action, "Docusign API request", whose schema covers the endpoints above. Anything defined in the [Docusign API](https://developers.docusign.com/docs/esign-rest-api/reference/) can be accessed through Serval. ## Get your credentials You need a Docusign app configured for the Authorization Code grant, with one Secret Key and Serval's Redirect URI registered. Docusign only lets you create new apps in a developer (sandbox) account - production use requires promoting the app through Docusign's Go-Live process. Full provider documentation: [Authorization Code Grant (Docusign docs)](https://developers.docusign.com/platform/auth/authcode/). If the Production admin page shows "You cannot create an integration key in production", that is expected - create the app in a [developer account](https://developers.docusign.com/platform/account/) first, then promote it later via [Go-Live](https://developers.docusign.com/platform/go-live/). Sign in at the [Demo / developer sandbox admin page](https://apps-d.docusign.com/admin/apps-and-keys) for a developer account, or the [Production admin page](https://apps.docusign.com/admin/apps-and-keys) for a promoted production app. Click **Add App and Integration Key** and enter an app name (for example, Serval) - this is what users see on the Docusign consent screen. Copy the auto-generated **Integration Key**; this is your Client ID. Under **Integration Type**, select **Private custom integration**. Do not pick Public or Embedded integration - those are for very different distribution models, and your Integration Key never leaves your Docusign tenant. In the **Authentication** section's User Application block, answer **Yes** to "Is your application able to securely store a client secret?" (this auto-selects Authorization Code Grant), and leave **Require Proof Key for Code Exchange (PKCE)** unchecked. Under **Secret Keys**, click **+ Add Secret Key**. Copy it immediately; this is your Client Secret. If you lose it, generate a new one and reconnect Serval. Do not generate or upload RSA keypairs. Those are for Docusign's JWT Grant flow, which Serval does not use - generating a keypair here does nothing for the Serval integration. In Serval, open **Integrations > All integrations > Docusign > Connect** and copy the **Redirect URI** shown at the top of the modal. In Docusign, go to **Additional Settings > Redirect URIs > + Add URI** and paste it exactly. Leave **CORS Configuration** empty (Serval calls Docusign server-to-server), then click **Save** at the bottom of the page - selections do not persist without saving. Docusign reveals each Secret Key one time only, and the Redirect URI must match exactly - any difference in scheme, host, path, or trailing slash makes Docusign reject the OAuth callback with a "redirect\_uri\_mismatch" error. ### Settings recap After saving, your Docusign app should match this: | Section | Setting | Value | | - | - | - | | General Info | App Name | Your choice (for example, Serval) | | General Info | Integration Key | Auto-generated - copy as your Client ID | | - | Integration Type | **Private custom integration** | | Authentication | Can securely store client secret? | **Yes** | | Authentication | Authentication Method | Authorization Code Grant | | Authentication | Require PKCE | **Unchecked** | | Authentication | Secret Keys | One added - copy as your Client Secret | | Service Integration | RSA Keypairs | None - leave empty | | Additional Settings | Redirect URIs | One entry - the URI shown in Serval's connect modal | | Additional Settings | CORS Configuration | Empty - no origins, no methods | ## Connect in Serval Go to **Integrations > All integrations > Docusign** and click **Connect**. The "Connect Docusign" modal opens; its intro text links straight to the Docusign Apps and Keys admin pages if you still need to create the app. The **Redirect URI** field at the top is read-only with a **Copy** button (it reads "Copied" for a moment after clicking). Helper text: "Add this as a Redirect URI in your Docusign app's Additional Settings section." Make sure this exact value is registered in your Docusign app before continuing. Pick **Production** or **Demo**; the default is Production. Helper text: "Choose Production if your Docusign app was created at apps.docusign.com, or Demo if it was created in a developer account at apps-d.docusign.com." Text field with placeholder "Paste your Docusign Integration Key". Surrounding whitespace is trimmed before the value is submitted. Password field with placeholder "Paste your Docusign Secret Key". Also trimmed of surrounding whitespace before submission. The button stays disabled until both key fields are filled in (whitespace-only values count as blank). It reads "Connecting..." while submitting, then your browser is sent to Docusign's sign-in and consent screen. Approve access, and Serval completes the connection - it is bound to your default Docusign account and named after that account. Complete the Docusign consent step within 10 minutes of clicking **Connect to Docusign** - the submitted credentials are held only that long before the flow expires. There is no in-place credential editing for this integration. To rotate the Secret Key or change any setting, reconnect through the full flow; reconnecting from the existing Docusign app instance updates the same connection rather than creating a duplicate. ## Verifying the connection The Docusign integration ships one health check: * **Test Docusign Connection** - asks Docusign for the connected account's details using the stored connection, verifying Serval can authenticate and reach your account. * Success: `Successfully connected to Docusign account "[name]".` (if Docusign does not return an account name, the message says "your account" instead) * Failure: `Unable to reach Docusign. Verify the OAuth credentials are valid and the account has not been deactivated.` If the test is green but workflows touch the wrong envelopes or templates, the connection may be bound to the consenting user's default Docusign account rather than the one you intended. Reconnect and choose the correct account on Docusign's consent screen. ## Gotchas and troubleshooting Production apps (apps.docusign.com) and Demo apps (apps-d.docusign.com) authenticate against different Docusign hosts. Serval treats any Environment value other than Demo - including blank - as Production, so picking the wrong option means your keys simply will not validate. Match the Environment to where the app was created. Serval runs a plain Authorization Code exchange, so a Docusign app with **Require PKCE** checked will reject the callback. RSA keypairs, the JWT Grant flow, and the impersonation scope are not used anywhere - Serval requests exactly the signature and extended scopes (extended is what makes Docusign issue a refresh token, so the connection stays alive without re-consenting hourly). See the [OAuth scopes reference](https://developers.docusign.com/platform/auth/reference/scopes/). The credentials you submit are cached for only 10 minutes between starting the flow and Docusign redirecting back. Taking longer surfaces "Invalid or expired OAuth state" or "OAuth session expired, please try again" - re-open the connect modal and start again. There is no update-credentials form for Docusign. If you regenerate the Secret Key in Docusign (or the app's consent is revoked on the Docusign side), token refresh starts failing and the health check goes red. A connect attempt with a wrong or regenerated Secret Key fails at Docusign's token exchange - Docusign reports an "invalid\_grant" error and Serval shows "Failed to exchange authorization code". Reconnect through the full connect flow with the new key; reconnecting from the existing app instance updates the connection in place. After consent, Serval binds the connection to the consenting user's default account (or the first account returned) and names it after that account - or after the account ID if Docusign returns no name. If the user has no accounts, connecting fails with "No Docusign accounts found for this user"; an account missing its API address fails with "Docusign did not return an API base URL for the account". To target a different account, reconnect and pick it at consent time. Docusign only allows app creation in developer accounts. Before promoting, the Integration Key needs at least 20 successful, distinct API calls against the developer sandbox (running real Serval workflows accumulates these). Then, in the developer sandbox admin, open the app and use **Actions > Start Review** - Docusign validates your API-call history and lets you promote the Integration Key into each production data center you need via [Go-Live](https://developers.docusign.com/platform/go-live/). Production uses a different Secret Key than the sandbox - after promoting, re-register the Redirect URI, generate a new production Secret Key, and reconnect Serval with Environment set to Production. Serval does not ship a shared Docusign OAuth app. You supply your own app's Integration Key and Secret Key at connect time; Serval stores them with the connection and reuses them for automatic token refresh. Each connection is bound to one Docusign app and one account. Docusign serves its API from region-specific data centers (for example, na4.docusign.net, eu.docusign.net, or demo.docusign.net for Demo accounts). Serval captures your account's home data center during the connect flow and routes all workflow calls there automatically - there is nothing to configure. Workflow traffic from Serval only ever goes to hosts under docusign.net. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Docusign integration. # Drata Source: https://docs.serval.com/sections/integrations/drata Connect Serval to Drata's Public API v2 with read-only access to compliance data. ## About Drata The Drata integration lets Serval workflows read compliance data from Drata's Public API v2. It includes the complete published GET surface for assets, audits, controls, evidence, frameworks, monitoring tests, personnel, policies, risks, vendors, workspaces, and related resources. This integration is deliberately read-only. Serval exposes only GET operations and rejects any non-GET request before credentials are added. **Authentication:** A Drata API key with **All read** access. Serval stores the key securely and sends it as a bearer token only to Drata's published US, EU, or APAC Public API host. **Data sync:** On demand. Serval reads data from Drata when a workflow runs and does not perform a background sync. ## Create a read-only API key In Drata, open **Settings**, then select **API Keys**. Select **Create API Key**, enter a descriptive name such as Serval Read Only, and choose an expiration policy that matches your security requirements. For **Access**, select **All read**. Do not select **All read and write**; the Serval integration cannot issue write requests. Save the full key immediately. Drata displays it only once. See [Drata's API-key guide](https://help.drata.com/en/articles/6695964-drata-public-api) for the current setup steps, IP allowlisting, and key lifecycle details. ## Connect in Serval Enter a recognizable instance name, such as Production. Choose United States, European Union, or Asia Pacific to match the location of your Drata account. Paste the complete Drata API key and submit the form. ## Verify the connection Serval checks that it can read company information, personnel, vendors, and workspaces. A failed check normally means the API key is invalid, the wrong region was selected, Drata's terms have not been accepted, or the key lacks the corresponding read permission. Drata enforces a limit of 500 requests per minute per source IP. List endpoints use cursor-based pagination and accept up to 500 results per request. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Drata integration. # Dropbox Source: https://docs.serval.com/sections/integrations/dropbox Dropbox is a cloud file storage and sharing platform - Serval connects with your own Dropbox app so workflows can browse, search, organize, and share files on demand. ## About Dropbox Dropbox is a cloud file storage and sharing platform. Serval connects using a bring-your-own-app model: your team creates its own Dropbox app and pastes its App key and App secret into Serval's Connect modal - Serval does not own a shared Dropbox app. Serval requests offline access during authorization, so Dropbox issues a long-lived refresh token alongside the short-lived (roughly 4-hour) access token, and Serval renews the access token for you automatically. After connecting, the installation is named from the connected account: the Dropbox team name if the account belongs to a team, otherwise the display name, then email, then ID. **Authentication:** Bring-your-own Dropbox app OAuth 2.0 (authorization code), with automatic token refresh. **Data sync:** On demand only. Workflows call Dropbox when they run; there is no background or scheduled sync, and no prebuilt workflows are installed with this integration. ## What the Dropbox integration enables | Capability | Description | | - | - | | Account and usage info | Look up the connected account, other Dropbox users, and storage usage. | | Browse files and folders | List folder contents (with pagination for large folders) and read file or folder details. | | Search | Find files and folders with filters for path, file status, filename-only matching, extensions, and categories. | | Manage files and folders | Create folders, and delete, move, or copy files and folders. | | Sharing | Generate temporary download links, create shared links with settings, list and revoke shared links, share folders, and add folder members. | | Generic API access | One "Dropbox API request" action reaches every supported Dropbox operation, and new operations can be added on request. | Anything defined in the [Dropbox API](https://www.dropbox.com/developers/documentation/http/documentation) can be accessed through Serval. ## Get your credentials Serval connects through a Scoped access Dropbox app that you own, created in the [Dropbox App Console](https://www.dropbox.com/developers/apps). You need the app's App key and App secret from its Settings tab, plus Serval's redirect URI added to the app. See Dropbox's [OAuth guide](https://developers.dropbox.com/oauth-guide) for background. In the Dropbox App Console, click **Create app**. Choose **Scoped access** for the API and **Full Dropbox** for the access type (or **App folder** if you only need access within Apps/\). On the **Permissions** tab, enable all seven scopes Serval requests: account\_info.read, files.metadata.read, files.metadata.write, files.content.read, files.content.write, sharing.read, and sharing.write. Scroll to the bottom of the Permissions tab and click **Submit**. Dropbox requires an explicit submit for permission changes. On the **Settings** tab, under **Redirect URIs**, paste the redirect URI shown in Serval's Connect Dropbox modal (use the modal's Copy button) and click **Add**. Copy both values from the Settings tab. You will paste them into Serval's Connect Dropbox modal. Dropbox ignores permission toggles until you click **Submit** at the bottom of the Permissions tab. Unsaved scopes cause an invalid\_scope error when you try to connect. The redirect URI is environment-specific. Always copy it from Serval's Connect modal - never type it by hand or reuse one from another environment. ## Connect in Serval In Serval, add the **Dropbox** integration to open the **Connect Dropbox** modal. It shows a read-only **Redirect URI** field with a Copy button (the button reads "Copy" and switches to "Copied" for 2 seconds). Its helper text reads: "Add this as a Redirect URI in your Dropbox app's Settings tab." Confirm this exact value is saved in your Dropbox app before continuing. Paste the App key from your Dropbox app's Settings tab. The field's placeholder is "Enter your Dropbox App key". Leading and trailing spaces are trimmed automatically. Paste the App secret from the same Settings tab. The field is password-masked, with placeholder "Enter your Dropbox App secret". The button stays disabled until both fields are filled in, and reads "Connecting..." while Serval starts the authorization. You are sent to Dropbox to approve access, then returned to Serval with the connection ready to use. Finish the Dropbox approval within 10 minutes of clicking **Connect to Dropbox**. If the window lapses, just reopen the Connect modal and start again. There is no in-place credential editing for this integration. If you rotate the App secret in the Dropbox App Console, reconnect the integration and enter the new values. ## Verifying the connection The Dropbox integration has no automated health checks in Serval, so nothing runs after you connect and there is no pass/fail status to look for. To verify the connection: 1. Create or run a simple workflow that reads Dropbox data - for example, one that looks up the connected account or lists a folder's contents. 2. If the workflow returns Dropbox data, the connection works. 3. If it fails with an authentication error, reconnect the integration with the current App key and App secret from your Dropbox app's Settings tab. A simple account lookup can succeed even when file access is limited. If basic reads work but workflows cannot see files you expect, check the Dropbox app's access type: an **App folder** app can only reach files inside Apps/\. Create a **Full Dropbox** app and reconnect to reach the whole account. ## Gotchas and troubleshooting Serval requests a fixed set of seven permissions on every connection: account\_info.read, files.metadata.read, files.metadata.write, files.content.read, files.content.write, sharing.read, and sharing.write. If any are missing from your Dropbox app's Permissions tab, Dropbox rejects the connection with an invalid\_scope error. Dropbox also ignores permission toggles until you click **Submit** at the bottom of the Permissions tab - enabling a scope without submitting has no effect. The redirect URI must be added to your Dropbox app's Redirect URIs (Settings tab) exactly as shown in Serval's Connect modal. The value is environment-specific, so a hand-typed or stale URI causes Dropbox to fail the authorization with a redirect URI mismatch. Use the modal's Copy button and re-add the value if in doubt. Serval holds your App key and App secret for at most 10 minutes between clicking **Connect to Dropbox** and approving on Dropbox's consent screen. Taking longer produces one of these errors. Reopen the Connect modal and restart the flow - nothing is broken on the Dropbox side. If you regenerate the App secret in the Dropbox App Console, Serval's stored copy becomes stale and token refresh starts failing once the current access token expires (within about 4 hours). There is no credential-edit screen for this integration - reconnect it with the new App secret to fix the connection. Dropbox only issues a long-lived refresh token when the connection explicitly asks for offline access, which Serval's generic custom-HTTP connection flow cannot do. Connections made that way get only a roughly 4-hour access token and then stop working. Always connect Dropbox through this native integration, which captures the refresh token and renews access automatically. Dropbox requires a JSON body on every call, even for operations that take no inputs - the convention is a literal null. The "Dropbox API request" action sends null automatically when no body is provided, so simple lookups like the current-account and storage-usage operations work out of the box. If a workflow sets the body explicitly for one of these operations, set it to null rather than leaving it empty. Team administration (member management, groups, team reporting) requires a team-scoped Dropbox token. Serval deliberately requests only user-scoped permissions, because adding any team scope would change the token type and break every user-level capability the integration provides. Connect as the user whose files you need to work with. Serval's outbound allow-list permits both api.dropboxapi.com and content.dropboxapi.com, but the "Dropbox API request" action targets only the standard API host, and the integration models only operations on that host. Bulk file content transfer through the content host is not available - use temporary download links and shared links to move file contents instead. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Dropbox integration. # Duo Security Source: https://docs.serval.com/sections/integrations/duo Connect Serval to Cisco Duo so workflows can manage users, MFA devices, bypass codes, and logs through the Duo Admin API, and optionally send Duo Push prompts through the Auth API. ## About Duo Security Cisco Duo is a multi-factor authentication and device-trust platform. The Serval Duo integration connects to your Duo account's **Admin API** application, giving workflows typed access to users, groups, phones, hardware tokens, WebAuthn credentials, bypass codes, administrators, logs, and account settings. Optionally, you can also attach an **Auth API** application to send Duo Push prompts and run pre-authentication checks from workflows. The integration is marked **Beta** in Serval's connect UI. **Authentication:** Duo's signed-request scheme. Every API call is individually signed with HMAC using your application's integration key and secret key; there are no bearer tokens to rotate. Admin API and Auth API are separate Duo application types with separate key pairs, and Serval automatically signs each request with the right pair based on the endpoint. **Data sync:** On demand only. There is no background user or group sync. ## What the Duo integration enables | Capability | Description | | - | - | | Duo Admin API request | Typed requests across the Admin API: users (create, modify, delete, enroll), groups, phones and activations, hardware tokens, WebAuthn credentials, bypass codes, administrators, administrative units, authentication/administrator/telephony logs, Trust Monitor events, settings, and account info. | | Duo Auth API request | Optional: `/auth/v2` endpoints such as `preauth` (which factors a user can use) and `auth` (send a Duo Push and wait for the result). Requires Auth API credentials. | | Endpoint discovery | Both API catalogs are indexed separately for workflow authoring, so the agent won't confuse Admin API and Auth API endpoints. | The Policies API, Passport API, and Integrations v2/v3 API are not available through this integration: Duo requires its newer v5 request signing for those endpoint groups, and this integration signs with v2. Everything else on the Admin API accepts v2-signed requests. ## Get your credentials You need your Duo **API hostname** and an **Admin API** application's integration key and secret key. Optionally, add an **Auth API** application's keys to enable `/auth/v2` workflows. Only administrators with the **Owner** role can create or view Admin API applications. Go to **Applications → Protect an Application**, search for **Admin API**, and click **Protect**. If an Admin API application already exists, you can reuse it. On the application page, grant only what your workflows need. **Grant resource - Read/Write** covers users, groups, phones, and bypass codes; **Grant read log** covers authentication and administrator logs; **Grant administrators** covers admin management. Copy the **integration key**, **secret key**, and **API hostname** (e.g. `api-xxxxxxxx.duosecurity.com`) from the application page. To send Duo Push prompts from workflows, also protect an **Auth API** application and copy its separate integration key and secret key. The API hostname is the same for all applications in your account. The Admin API secret key grants administrative access to your Duo account, limited only by the application's permission grants. Grant the minimum permissions your workflows need, and rotate the secret key in Duo if it is ever exposed. ## Connect in Serval In Serval, add the Duo Security integration. It is labeled **Beta**. Paste your API hostname, e.g. `api-xxxxxxxx.duosecurity.com` (`api-xxxxxxxx.duofederal.com` for federal accounts). Paste the Admin API application's integration key, and its secret key in the password field. Both must be provided together; needed for `/admin` and `/accounts` endpoints. Paste the Auth API application's keys to enable `/auth/v2` endpoints. Both must be provided together; leave both blank to skip. Submit the form. Serval runs three health checks (below). Every field is optional at save time, so you can create the connection first and add credentials later; API calls and health checks report exactly which credentials are missing. When editing an existing connection, blank or obfuscated fields keep their stored values. Paste a new secret key to rotate credentials without re-entering everything else. ## Verifying the connection Three health checks run after you connect: 1. **Test Duo Admin API Connection** — fetches one user from `/admin/v1/users`. Confirms the hostname, integration key, and secret key are correct. Skipped (reported as healthy) when Admin API credentials are not configured. 2. **List Duo Groups** — fetches one group. Confirms resource read access. Skipped when Admin API credentials are not configured. 3. **Test Duo Auth API Connection** — calls `/auth/v2/check` with the Auth API credentials. Skipped when no Auth API credentials are configured. A 401 response usually means a wrong secret key or API hostname. A 403 means the request was signed correctly but the application lacks the permission grant for that endpoint — adjust the grants on the application page in the Duo Admin Panel. ## Gotchas and troubleshooting The two APIs use separate credential pairs from separate Duo applications. Admin API keys cannot call `/auth/v2` endpoints and vice versa. Serval routes each request to the right pair automatically, but both must be configured in the connection for both APIs to work. Duo's request format only supports flat parameters. Where an endpoint accepts a list (e.g. bypass codes to create), pass a comma-separated string, not an array. Each Admin API application carries explicit grants (resource read/write, log read, administrators, settings). An endpoint outside the granted set returns 403 even with valid keys. `DELETE /admin/v1/users/{user_id}` moves the user to the trash, where they remain restorable for 30 days before permanent deletion. Use the bulk restore endpoint to recover. Duo returns 429 when an endpoint is called too frequently; bulk user creation is limited to 50 calls per minute. Serval retries with backoff, but long-running loops over large user sets should paginate with `limit`/`offset` rather than issuing per-user calls where a list endpoint exists. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Duo Security integration. # Egencia by Amex GBT Source: https://docs.serval.com/sections/integrations/egencia Connect Egencia (by Amex GBT) to Serval to automate corporate travel and expense workflows. ## About Egencia Egencia (an American Express Global Business Travel brand) is a corporate travel management platform. Connecting Egencia to Serval lets your team build workflows that read trips, bookings, traveler profiles, expenses, reporting, and duty-of-care data through the **Egencia OpenConnect APIs**. This integration is currently in **beta**. The available endpoint surface is modeled from Egencia's public developer documentation and is reconciled with the official Egencia API specification supplied during developer on-boarding. ## What the Egencia integration enables | Capability | Description | | - | - | | Bookings & trips | Retrieve trip and booking details, segments, and itineraries | | User sync | Read, create, update, and deactivate traveler user profiles | | Expense | Read travel expenses, invoices, and receipt artifacts | | Reporting | Request and retrieve reporting data and dashboards | | Duty of care | Locate travelers on the road for safety and compliance | Anything available through your Egencia API client can be used from Serval workflows. *** ## Egencia configuration ### Prerequisites Before connecting Egencia, make sure you have: * An Egencia account with the **OpenConnect APIs** provisioned * API **Client credentials** (a Client ID and Client Secret) issued by Egencia during API on-boarding Serval authenticates with Egencia using standard OAuth 2.0 **client credentials** (server-to-server). It exchanges your Client ID and Secret for a short-lived bearer token at `https://apis.egencia.com/auth/v1/token`, then sends that token in the `Authorization: Bearer` header on each request. You do not need to configure a redirect URL. ### Obtain API credentials from Egencia Work with your Egencia account team to enable the OpenConnect APIs and begin API on-boarding for your account. During on-boarding, Egencia issues a **Client ID** and **Client Secret**. These authenticate Serval to the Egencia APIs. Store the Client Secret securely. Egencia may not show it again after on-boarding. *** ## Serval configuration 1. In Serval, go to **Integrations > All integrations > Egencia by Amex GBT > Connect** 2. Enter the following information: | Field | Description | | - | - | | Account Name | A label for this Egencia account (used to identify the connection in Serval) | | Client ID | The Egencia API **Client ID** | | Client Secret | The Egencia API **Client Secret** | 3. Click **Save** After the connection is saved, Serval can call the Egencia OpenConnect APIs in workflows. You can confirm connectivity with the built-in healthchecks (test connection, list bookings, list reports). *** ## Additional resources * [Egencia Developer Center](https://www.amexglobalbusinesstravel.com/egencia-developer-center/api-overview) Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Egencia integration. # Egnyte Source: https://docs.serval.com/sections/integrations/egnyte Connect Egnyte, the cloud content collaboration and file sharing platform, so Serval workflows can manage files and folders, search content, and look up users and groups in your Egnyte domain. ## About Egnyte Egnyte is a cloud content collaboration and file sharing platform. The Serval Egnyte integration is a bring-your-own-app (BYO) OAuth integration: your team registers its own application in the Egnyte Developer Portal and connects it to Serval with your Egnyte domain, Client ID (API Key), and Client Secret. Once connected, workflows can manage files and folders, search content, and look up users and groups, acting with the permissions of the Egnyte user who approved the connection. **Authentication:** Bring-your-own Egnyte OAuth app (authorization code grant) - you supply your Egnyte domain, Client ID (API Key), and Client Secret, then an Egnyte user approves access. **Data sync:** On-demand only. Connecting Egnyte does not install any background sync workflows; Serval calls Egnyte only when a workflow runs an Egnyte action, plus a periodic connection health check. ## What the Egnyte integration enables | Capability | Description | | - | - | | Egnyte API request | A general-purpose workflow action that calls a curated set of Egnyte Public API operations through your connection. | | User info | Look up the Egnyte user the connection acts as (username, name, email, role, and user type). Also used as the connection health probe. | | Files and folders | List folder contents, read file and folder details, create folders, move or copy items, and delete files or folders. | | Search | Search across files and folders, with folder scoping, a file-or-folder type filter, and pagination. | | Users (read) | List Egnyte users with filtering, or look up a single user. | | Groups (read) | List Egnyte groups, or look up a single group and its members. | These capabilities are a curated subset of the [Egnyte Public API](https://developers.egnyte.com/docs) rather than the full API surface. The set is expected to grow over time. ## Get your credentials Serval does not ship with a built-in Egnyte app, so you first create an OAuth application on your own Egnyte domain. Egnyte's official references are the [Public API Authentication guide](https://developers.egnyte.com/docs/read/Public_API_Authentication) and the [Developers Portal step-by-step guide](https://helpdesk.egnyte.com/hc/en-us/articles/39833196166797-Apigee-based-Developers-Portal-Step-by-Step-Guide). Register or sign in at the [Egnyte Developer Portal](https://developers.egnyte.com/member/register). Click your username in the top-right, select **Apps**, then **New App**. Provide the app name, description, and your Egnyte domain. Choose **Authorization Code** as the grant type. Other grant types will not work with Serval. In the app's **Registered OAuth Redirect URI** field, paste the exact Redirect URI shown in Serval's Connect Egnyte modal. Use the Copy button in the modal - the value is environment-specific, so do not type it by hand. Make sure all five scopes Serval requests are available to the app: Egnyte.filesystem, Egnyte.user, Egnyte.group, Egnyte.permission, and Egnyte.link. Egnyte's portal documentation notes that a newly requested API key can remain inactive for up to 24 hours until approved. Wait until the key shows as Active. From the app page, copy the **Client ID (API Key)** and **Client Secret**. You will paste these into Serval next, along with your Egnyte subdomain (for example, acme if you sign in at [https://acme.egnyte.com](https://acme.egnyte.com)). Serval requests the same five scopes on every connection. If any of Egnyte.filesystem, Egnyte.user, Egnyte.group, Egnyte.permission, or Egnyte.link is missing from the app, Egnyte returns invalid\_scope during authorization and the connection fails before you ever see a consent screen. The connection will act as whichever Egnyte user approves it. Plan to complete the Serval connect flow signed in as an Egnyte account whose permissions cover everything your workflows need. ## Connect in Serval At the top of the modal is a read-only **Redirect URI** field with a Copy button, with the instruction "Add this as a Redirect URI in your Egnyte app's settings." Confirm you registered this exact value on your Egnyte app before continuing. Enter just your subdomain - for example, acme if you sign in at [https://acme.egnyte.com](https://acme.egnyte.com). The field shows a fixed .egnyte.com suffix beside the input, and pasting acme.egnyte.com or the full sign-in URL also works; Serval trims it down to the bare subdomain. If the value still fails validation when you click Connect, the modal shows "Failed to initiate OAuth: subdomain must be a valid Egnyte subdomain (letters, digits, and dashes only)". Paste the API Key from your Egnyte app. Surrounding whitespace is trimmed automatically. Paste the Client Secret from the same app. The input is hidden as you type and whitespace is trimmed. The **Connect to Egnyte** button stays disabled until all three required fields are filled in. When you click it, Serval sends you to Egnyte's sign-in and authorization page on your own domain. Sign in and approve the request. The connection appears in Serval named after your subdomain with the approving user's Egnyte username in parentheses, for example acme (jsmith) - or just the subdomain if the user lookup fails. Complete the Egnyte approval within 10 minutes of clicking **Connect to Egnyte**. The credentials you entered are held only briefly between starting the flow and Egnyte's callback; if you linger on the consent screen past that window, the flow fails with "Invalid or expired OAuth state" or "OAuth session expired, please try again" and you must start over. There is no separate edit form for Egnyte credentials. If you rotate the Client Secret or replace the app in the Egnyte portal, reconnect through the Connect Egnyte modal with the new values. ## Verifying the connection Serval periodically verifies the connection by asking Egnyte for the profile of the user who authorized it, refreshing the access token first if needed using your stored Client ID and Client Secret. If Egnyte returns the user, the connection reports healthy; if the token can no longer be refreshed (for example, after a Client Secret rotation or app deletion), the check fails. This integration has no custom success or failure messages beyond the standard connection status. A healthy connection proves Serval can authenticate as the connected user - it does not prove that user can reach a specific folder. If the connection looks fine but a workflow's file or folder action fails, check the authorizing user's permissions on that path in Egnyte. ## Gotchas and troubleshooting The most common cause is a Redirect URI mismatch. The Connect Egnyte modal shows the exact, environment-specific Redirect URI with a Copy button; that precise value must be in your Egnyte app's Registered OAuth Redirect URI field. Never hand-construct it. Serval requests a fixed scope set on every connection: Egnyte.filesystem, Egnyte.user, Egnyte.group, Egnyte.permission, and Egnyte.link. If your app does not have all five available, Egnyte rejects the authorization. Enable the missing scopes on the app and reconnect. The credentials you enter are held for 10 minutes between starting the connect flow and completing Egnyte's approval. If you take longer than that on Egnyte's side, the callback fails with "Invalid or expired OAuth state" or "OAuth session expired, please try again". Restart the connect flow from the modal. If the Client ID or Client Secret you entered does not match the app you approved against, Serval cannot redeem the authorization code and the flow ends with "Failed to exchange authorization code". Double-check both values in the Egnyte Developer Portal and restart the connect flow. Per Egnyte's developer portal documentation, a newly requested API key can remain inactive for up to 24 hours until Egnyte approves it. Connecting with a not-yet-active key fails; wait until the key's status shows Active in the portal, then connect. Serval stores your Client ID and Client Secret with the connection and uses them to refresh access tokens. If the secret is rotated or the app is deleted in the Egnyte portal, refresh fails and the connection goes unhealthy. Reconnect through the Connect Egnyte modal with the new credentials - there is no separate credential-update form for Egnyte. The connection acts as the Egnyte user who approved it, and every call is bounded by that user's Egnyte permissions. If a file, search, user, or group action fails, verify the authorizing account can perform the same action directly in Egnyte, or reconnect with a more privileged account. The domain field is forgiving - acme, acme.egnyte.com, and the full sign-in URL all normalize to the bare subdomain. After normalization, the value must contain only letters, digits, and dashes (1-63 characters, no leading or trailing dash). Anything else is rejected with "Failed to initiate OAuth: subdomain must be a valid Egnyte subdomain (letters, digits, and dashes only)". Serval does not own an Egnyte OAuth app. Every team registers its own application on its own Egnyte domain and supplies that app's Client ID (API Key) and Client Secret. Egnyte's sign-in and approval pages are also per-domain, so each connection authorizes against your own Egnyte address. The surface area is intentionally small: a hand-maintained set of Egnyte operations exposed through the Egnyte API request action, with no shipped sync workflows or helper actions yet. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Egnyte integration. # Accruent EMS Source: https://docs.serval.com/sections/integrations/ems Connect Accruent EMS to Serval to automate room, desk, and event scheduling workflows. ## About Accruent EMS Accruent EMS (formerly EMS Software) is a workplace, room, desk, and event scheduling platform used across higher education and corporate offices. Connecting EMS to Serval lets your team build workflows that read from and write to EMS through the **EMS Platform Services API**. This integration targets the EMS **Platform Services API** specifically. It is scoped to EMS and does not cover other Accruent products (Maintenance Connection, Lucernex, Meridian, etc.), which expose their own separate APIs. ## What the Accruent EMS integration enables | Capability | Description | | - | - | | Space data | Look up buildings, rooms, room types, areas, floors, and setup types | | Bookings & reservations | Read and manage bookings, reservations, and statuses | | Groups & users | Look up groups, group types, web users, and related directory data | | Service orders | Read and manage service orders and related resources | Anything available through your EMS Platform Services integration client can be used from Serval workflows. *** ## Accruent EMS configuration ### Prerequisites Before connecting EMS, make sure you have: * Administrator access to the EMS Platform Services Admin (Configuration) portal * EMS Platform Services enabled for your environment * Your EMS API domain, such as `ems05.emscloudservice.com` (for EMS Cloud) * Permission to create an integration client (which provides a Client ID and Secret) Serval authenticates with EMS using a client (server-to-server) integration. It exchanges your Client ID and Secret for a short-lived token via `POST /platform/api/v1/clientauthentication`, then sends that token in the `x-ems-api-token` header on each request. You do not need to configure a redirect URL. ### Create an integration client in EMS In the EMS Admin (Platform Services Configuration) portal, go to the **Integrations** configuration area. Create a new integration client (sometimes called an "API client" or "Integration"). Use a recognizable name such as `Serval Integration`. Ensure the client has access to the EMS data your workflows need (for example, the buildings, rooms, bookings, and groups your automations will read or write). Save the client, then copy the generated **Client ID** and **Secret**. You will enter these in Serval. Store the secret securely. EMS may not show it again after you leave the client details page. *** ## Serval configuration 1. In Serval, go to **Integrations > All integrations > Accruent EMS > Connect** 2. Enter the following information: | Field | Description | | - | - | | API Domain | Your EMS instance domain, such as `ems05.emscloudservice.com`. Omit `https://` and any path. | | Client ID | The EMS integration client **Client ID** | | Client Secret | The EMS integration client **Secret** | 3. Click **Save** On save, Serval validates the credentials by minting an EMS client token. After the connection succeeds, Serval can call the EMS Platform Services API in workflows. You can confirm connectivity with the built-in healthchecks (test connection, list buildings, list rooms, list groups). *** ## Additional resources * [EMS Platform Services — Introduction](https://help.accruent.com/ems/Content/EMSPlatformServices/InstallationGuide/Introduction.html) * [EMS API home](https://help.accruent.com/ems/Content/OptionalFeatures/2_EMS_API_Home.htm) Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Accruent EMS integration. # Envoy Source: https://docs.serval.com/sections/integrations/envoy Connect Serval to Envoy, the workplace and visitor management platform, so workflows can list locations and sign-in flows, look up visitor invites, and create new visitor invitations. ## About Envoy Envoy is a workplace and visitor management platform covering locations, employees, visitor invites, entries, and sign-in flows. Serval connects to Envoy's v1 REST API using an Envoy Client API Key, letting workflows list locations and sign-in flows, retrieve visitor invites, create new visitor invitations, and reach anything else in the Envoy API through a generic request action. Serval only ever talks to Envoy's official API address (api.envoy.com), so workflows cannot use this connection to call any other service. **Authentication:** API key (Envoy Client API Key), sent with every request Serval makes on your behalf. **Data sync:** On-demand only. Workflows call Envoy when they run, and two health checks verify connectivity. Nothing is imported into Serval automatically, and there is no background sync or webhook ingestion. ## What the Envoy integration enables | Capability | Description | | - | - | | Envoy API request | Call any Envoy v1 REST API operation on demand, with optional body and query parameters. | | Get Envoy Invites | Starter workflow that retrieves all visitor invites, including pending and completed invitations. Installs with installer approval by default. | | Create New Envoy Invite | Starter workflow that creates a new visitor invitation with visitor details, host information, and the expected arrival date and time. It looks up the location by name and the host employee by name and email, and the visitor receives an email invitation to pre-register. Installs with installer approval by default. | | Get Envoy Locations | Starter workflow that lists every location in your Envoy account, including names and IDs. Installs with no approval required by default. | | Get Envoy Flows | Starter workflow that retrieves all sign-in flows, which define the visitor check-in process at each location. Installs with no approval required by default. | Anything defined in the [Envoy API](https://developer.envoy.com/) can be accessed through Serval. ## Get your credentials Serval authenticates with a Client API Key, which Envoy issues when you create an integration in the [Envoy Dev Dashboard](https://dashboard.envoy.com/dev-dashboard). See the [Envoy developer documentation](https://developer.envoy.com/) for background. In the [Envoy employee directory](https://dashboard.envoy.com/employees), click **Add Employee** and create a dedicated API user with a service-account email address. Assign it the **Global Admin** role and disable **Show employee as a host on the Visitors Kiosk**. Sign in as the dedicated API user from the previous step, then open the [Envoy Dev Dashboard](https://dashboard.envoy.com/dev-dashboard) and click **Create New**. Performing this and the following steps as that user means the integration and its Client API Key are owned by a stable service account rather than a personal account. Give it a name (for example, "Serval Integration") and a short description. At minimum, grant read access to companies and locations. Add invite, visitor, and employee scopes if you plan to use the invite workflows. Check **Is the integration ready to be displayed?** and click **Save**. Expand the **Envoy API Credentials** section on the same page, locate the **Client API Key**, and copy it for the Serval connect form. Do not skip the scopes step. Serval's connection health checks read your company and location lists, so a key without those read scopes fails its health checks even if other calls work. ## Connect in Serval In Serval, add a new Envoy connection. **Instance Name** (required) is a friendly name to identify this integration instance inside Serval. Leaving it blank shows "This field is required". **API Key** (required) is a password field with the helper text "Your Envoy API key (Client API Key)". Paste the Client API Key you copied from the Envoy Dev Dashboard. Leaving it blank shows "This field is required". Submit the form. The key is stored encrypted, and afterward it displays as bullets plus its last 4 characters. If saving fails, you may see "Failed to install integration" or "Failed to save configuration. Please try again." Saving the form does not test your key against Envoy. A successful save only means the key was stored - run the health checks right after connecting to confirm it works. When editing an existing Envoy connection, the saved key appears in a disabled, obfuscated field with a **Replace** button (clicking it shows a password input with the placeholder "Enter new value"). Whenever you save the configure form again - even if you only changed the Instance Name - click **Replace** and paste the full API key before saving. Do not save with the key field left untouched or cleared. ## Verifying the connection The Envoy integration ships with two health checks: * **Test Envoy List Companies** confirms Serval can reach Envoy with your stored key by reading your company list. Success shows "Successfully connected to Envoy and retrieved companies list"; failure shows "Failed to connect to Envoy or list companies. Please check your API key and permissions." * **Test Envoy List Locations** does the same by reading your location list. Success shows "Successfully connected to Envoy and retrieved locations list"; failure shows "Failed to connect to Envoy or list locations. Please check your API key and permissions." Health checks green but the invite workflows fail? The checks only prove company and location read access. Go back to your integration in the Envoy Dev Dashboard and add invite, visitor, and employee scopes. ## Gotchas and troubleshooting Always re-enter the API key when you save the configure form for an existing connection, even for an unrelated change like renaming the instance: click **Replace** and paste the full key, then save. If the connection starts failing immediately after an edit, re-enter the key to restore it. The connect form saves without contacting Envoy, so a wrong or under-scoped key still reports a successful connection. Run the health checks (or the Get Envoy Locations starter workflow) right after connecting to confirm the key actually works. Both health checks read your company and location lists directly from Envoy. If the integration you created in the Envoy Dev Dashboard lacks scopes that permit reading companies and locations, health checks fail even when other scoped calls work. Add those read scopes to the integration in Envoy. The Envoy API request action automatically adds the v1 version prefix to any path that does not already start with it, so you can enter the path with or without the prefix. Do not write the prefix twice - the action does not strip duplicates, so a doubled version path fails. Always start the path with a forward slash: the prefix is joined directly onto whatever you enter, so a missing slash produces a malformed address. Only Envoy's API host is reachable through this connection, and any record IDs must be written directly into the path itself; there is no separate path-parameters input. That is expected. After connecting, the form shows the key as bullets plus its last 4 characters, and the stored value is encrypted. Use those trailing characters to confirm which key is saved before rotating or replacing it. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Envoy integration. # Exchange Online Source: https://docs.serval.com/sections/integrations/exchange-online Connect Microsoft Exchange Online to Serval to automate mailboxes, distribution groups, and other Exchange administration through Exchange Online PowerShell. ## About Exchange Online Exchange Online is Microsoft's cloud email and calendaring service, part of Microsoft 365. The Serval integration runs Exchange Online PowerShell to manage mailboxes, distribution groups, mail-enabled security groups, and dynamic distribution groups. It is a **separate integration** from [Microsoft Graph](/sections/integrations/microsoft-graph) (Microsoft 365): teams using both need both connected. Commercial connections use `login.microsoftonline.com` for sign-in and `outlook.office365.com` for Exchange Online. GCC High uses `login.microsoftonline.us` and `outlook.office365.us`. See Microsoft's [Exchange Online connection environments](https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/connect-exchangeonline?view=exchange-ps#-connectionuri). **Authentication:** Microsoft Entra ID app registration, using either a **Client Secret** or a **Certificate (PEM)**. Both methods use app-only access tokens. Choose the method approved for your app registration. **Data sync:** On-demand only. There is no background sync, entity ingestion, or scheduled polling - each action opens a fresh Exchange Online session on the Serval worker, runs, and disconnects. ## What the Exchange Online integration enables | Capability | Description | | - | - | | Get Mailbox | Look up a mailbox by identity, including its forwarding and address-list settings. | | Set Mailbox | Update a mailbox's display name, email forwarding, and whether it's hidden from the address list. | | Create Distribution Group | Create a new distribution group. | | Get Distribution Group | Look up a distribution group. | | Set Distribution Group | Update a distribution group's settings. | | Remove Distribution Group | Delete a distribution group. | | Get Distribution Group Members | List the members of a distribution group. | | Add Distribution Group Member | Add a member to a distribution group. | | Remove Distribution Group Member | Remove a member from a distribution group. | | Invoke Exchange Online Command | Run Exchange Online PowerShell commands inside a connected session - covers operations without a dedicated action, such as mail-enabled security groups, dynamic distribution groups, and disabling or removing mailboxes. | The **Invoke Exchange Online Command** action runs commands available to the connected app, subject to its permissions and Microsoft's app-only authentication support. ## Get your credentials Create an Entra ID app registration with `Exchange.ManageAsApp` and admin consent. Have an Exchange administrator prepare a custom PowerShell role group for the commands and recipient write scope your workflows need. Serval generates a script to register the app in Exchange and add it to that existing group. See Microsoft's [app-only authentication guide](https://learn.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#step-5-assign-role-permissions-to-the-application). In your cloud's Microsoft Entra admin center, search for **App registrations**, then select **New registration**. Choose **Accounts in this organizational directory only**, leave the Redirect URI blank, and register. From the app's **Overview** page, copy the **Application (client) ID** and the **Directory (tenant) ID**. In the app registration, go to **API permissions → Add a permission → APIs my organization uses → Office 365 Exchange Online → Application permissions**, select **Exchange.ManageAsApp**, then select **Add permissions** and **Grant admin consent**. For GCC High, follow Microsoft's [app manifest instructions](https://learn.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps#modify-the-app-manifest-to-assign-api-permissions). In the app registration, go to **Certificates & secrets → New client secret**. Copy the secret **value** immediately - Microsoft shows it only once. Generate a self-signed certificate so you have two files: a certificate file and a private key file (for example, with OpenSSL). Then prepare two things: * Upload the **certificate file only** to the app registration under **Certificates & secrets → Certificates**. * Combine the certificate and private key into a **single file** - that combined text is what you'll paste into Serval. Confirm the Exchange Online organization domain with your administrator. For **Commercial**, use the primary `.onmicrosoft.com` domain, such as `contoso.onmicrosoft.com`, in Serval's **Organization** field. In your cloud's Microsoft Entra admin center, go to **Enterprise Applications** (not App registrations), open your app, and copy its **Object ID**. You'll enter this in Serval's **Enterprise App Object ID** field. Have an administrator with the **Role Management** role open **Exchange admin center → Permissions → Admin roles → Add role group**. Create a custom role group, for example **Serval Recipient Management**, and select the recipient write scope approved for your workflows. This must be an **Exchange admin role group**. Creating an ordinary Microsoft 365 group, security group, or distribution group doesn't complete this step. See Microsoft's [role group setup instructions](https://learn.microsoft.com/en-us/exchange/permissions-exo/role-groups#use-the-eac-to-create-role-groups). On the **Permission** page of the role-group wizard, select the roles your workflows need. For example, for workflows that update existing mailboxes and manage distribution groups, select: * **Mail Recipients** for managing existing mailboxes. * **Distribution Groups** for managing distribution groups and their membership. These are example roles, not a complete permission set for every workflow or health check. Have your administrator confirm command coverage, including `Get-OrganizationConfig` if you plan to use the **Get Organization Config** health check. Continue through **Admins** to **Review and finish**, review the selections, and select **Add role group**. Serval's setup script adds the app's service principal later. Before running that script, reopen the group under **Admin roles**. Confirm the selected roles on the **Permission** tab and the write scope on the **General** tab. If you change the roles, select **Save** and reopen the group to confirm they persisted. Copy the group's exact name for Serval's **Approved Exchange role group** field. `Exchange.ManageAsApp` and admin consent don't grant the workflow's commands by themselves. Exchange PowerShell management roles determine command access. This setup uses an approved custom role group. Other assigned roles also contribute permissions, so adding a scoped group doesn't restrict a broader grant. ## Connect in Serval In Serval, open **Integrations**, find **Exchange Online**, and start a new connection. * **Cloud environment**: Select **Commercial** or **GCC High (US Government)** for your tenant. * **App (Client) ID**: Enter the app registration's Application (client) ID. * **Tenant (Directory) ID**: Enter the app registration's Directory (tenant) ID. * **Organization**: Enter the Microsoft 365 tenant domain. Serval trims whitespace and lowercases it. **Cloud environment** and **Organization** select the connection's destination. Saving these values doesn't verify that they belong to the configured tenant. Select **Client Secret** (the default) or **Certificate (PEM)**. Only the credential field for the selected method appears. * **Client Secret**: Paste the secret value from your app registration. * **Certificate (PEM)**: Paste the combined PEM certificate and private key. Use **Instance Name (Optional)** to describe the app's purpose, such as "Recipient management" or "Mailbox settings". If you leave it blank, Serval uses the **Organization** value followed by the first eight characters of the App (Client) ID, such as `contoso.onmicrosoft.com (bbbbbbbb)`. After saving, open the connection's settings and expand **Exchange Online PowerShell Setup**. Enter the **Approved Exchange role group** name and **Enterprise App Object ID**, then copy the script. The role group must already exist. Enter **Organization Management** only if its broad permissions are approved for this app. Have an Exchange administrator review and run the script in the intended tenant. It registers this app's service principal if needed, adds it to the named role group if needed, and disconnects. It doesn't create a role group or define its commands or scope. Exchange PowerShell role groups and recipient write scopes are separate from [Application RBAC permissions for Graph and EWS](https://learn.microsoft.com/en-us/exchange/permissions-exo/application-rbac). For example, **Application Exchange Full Access** grants Graph mailbox API access, not Exchange PowerShell commands. A write scope limits modifications; it doesn't establish an equivalent read boundary. **Credential rotation:** keep the same app and tenant, and paste the complete new Client Secret or Certificate. Blank or masked credential values retain the saved credential. When switching authentication methods, enter the new credential. Use a new connection and update the appropriate workflow bindings when changing apps or tenants. New connections keep their tenant and app identity fixed; older connections saved under a label retain their existing editing behavior. ## Use multiple scoped connections Connect each Entra app separately and give it a name that describes its purpose. Each saved connection has a selector that workflows can bind to. Keep existing saved selectors when updating credentials; don't reconstruct them from a tenant domain or app ID. Use the saved connection's settings to rename it, reconnect it, or change its cloud environment. A fresh Connect for an already connected app with a different cloud is refused. In TypeScript workflows, declare each selector directly in the workflow's context type and pass the named connection to each action. Catalyst receives the saved selectors alongside the connection names; ask Catalyst to bind the named connections. New selectors contain the lowercase, hyphenated Tenant (Directory) ID and App (Client) ID, joined by `/`. Earlier connections keep their saved labels. Replace the two saved-key placeholders below with the connections' actual selectors. This workflow returns a mailbox and a distribution group; **Get Distribution Group** also requires permission to list that group's members. ```typescript theme={null} import { workflow } from "serval/core"; import * as exchange from "serval/integrations/microsoft/powershell/exchange-online"; export const main = workflow({ name: "Inspect mailbox and distribution group", fn: async ( input: { mailboxIdentity: string; distributionGroupIdentity: string }, ctx: exchange.context.ExchangeOnlineIntegrationFromServiceInstanceID< "mailboxes", "saved-mailbox-connection-key" > & exchange.context.ExchangeOnlineIntegrationFromServiceInstanceID< "groups", "saved-group-connection-key" >, ) => { const mailbox = await exchange.getMailbox( { identity: input.mailboxIdentity }, ctx.integrations["exchange-online"].mailboxes, ); const group = await exchange.getDistributionGroup( { identity: input.distributionGroupIdentity }, ctx.integrations["exchange-online"].groups, ); return { mailbox, group }; }, }); ``` Keep selectors inline as shown. Type aliases, bare selector imports from `.../sdk/context`, and deeper namespace references aren't extracted as app bindings, even when TypeScript accepts them. Don't mix a named target with the unbound Exchange context in the same workflow. Use distinct aliases for distinct purposes. Two aliases can use the same saved selector when one app serves both purposes. Don't reuse one alias for different selectors. Serval doesn't choose an app based on the command's permissions, so use explicit bindings for scoped apps. When you test an unbound Exchange workflow through Catalyst and your team owns multiple Exchange connections, choose a connection before the run can start. This check uses the version being run, including historical versions and edits to temporary workflows, and runs again at startup in case the draft changed after your request. A version with explicit bindings or no Exchange use doesn't need this choice. Other runs can still use the oldest available connection if neither the code nor the run selects one. Bind scoped workflows explicitly before using them with multiple connections. ## Verifying the connection Serval runs three health checks against your tenant: | Health check | What it does | On success | | - | - | - | | Get Organization Config | Connects and reads your organization's configuration. | "Successfully connected to Exchange Online for organization: \[name]" | | List Mailboxes | Lists a small sample of mailboxes. | "Successfully listed mailboxes from Exchange Online (found \[number] in sample)" | | List Distribution Groups | Lists a small sample of distribution groups. | "Successfully listed distribution groups from Exchange Online (found \[number] in sample)" | Mailbox and distribution group checks can succeed with a sample count of zero. A check that returns no structured result fails; inspect its error before changing permissions. An unavailable check command can be outside the app's approved scope; it doesn't establish that the app has no management roles. In **Health Checks**, turn off only checks that an Exchange administrator confirms are intentionally outside that scope. **Unknown** or a disabled check doesn't confirm that a workflow operation works. Validate each required operation against an approved test recipient, including a recipient outside the intended write scope when testing scope restrictions. Successful health checks verify those read commands. They don't verify every workflow action, recipient write scope, or Microsoft 365 (Graph) connection. ## Gotchas and troubleshooting Check the command name, app-only support, and the app's approved Exchange PowerShell role group. An unavailable command doesn't prove that every management role is missing. If Exchange explicitly reports no management role assignment, ask an Exchange administrator to verify the service principal and its approved role group. Review health check commands separately: `Get-OrganizationConfig`, `Get-Mailbox`, and `Get-DistributionGroup`. Confirm the app has the `Exchange.ManageAsApp` application permission with admin consent granted, then run the post-save setup script. Make sure you used the **Enterprise Application** Object ID, not the App registration's Object ID. Microsoft can take a little while to apply new permissions and role assignments, so a just-fixed connection may keep failing briefly before it starts working. Connect and authorize each integration separately. You can use the same Entra app registration if it has the required permissions for both, or separate registrations with different scopes. Microsoft Graph treats distribution groups and mail-enabled security groups as read-only and doesn't support dynamic distribution groups. Use Exchange Online to manage them. Plain distribution groups have dedicated Serval actions; use **Invoke Exchange Online Command** for operations without a dedicated action. See Microsoft's [group types overview](https://learn.microsoft.com/en-us/graph/api/resources/groups-overview?view=graph-rest-1.0#types-of-groups-supported-in-microsoft-graph). Serval requires the certificate **and** the private key combined in a single paste - the text must contain both a certificate block and a private key block. Upload only the certificate file to Entra, but paste the combined certificate-plus-key file into Serval. Changing the Authentication Method on an existing connection requires the new credential in the same save - otherwise the save fails with an error that includes "Client Secret is required when switching to client secret authentication" or "Certificate (PEM) is required when switching to certificate authentication". Switching wipes the previously stored secrets, and even within the same method, saving a new client secret clears any stored certificate (and vice versa). Every action runs in a fresh session - Serval connects to Exchange Online at the start and disconnects at the end, with a default timeout of 120 seconds. Scripts that exceed the timeout are forcibly stopped and surface as an error. For long operations (large-tenant listings, bulk updates), raise the timeout setting on the **Invoke Exchange Online Command** action - the dedicated actions don't expose a timeout control. The Exchange Online module can write formatting escape codes to the console. Read results from the action's structured `json` result. PowerShell success-stream output is serialized automatically; `json` is null when the script produces no output. `$ErrorActionPreference` is set to `Stop`, so PowerShell errors stop the script. Exchange Online is action-only: there are no installable workflow templates, no synced entities, and no background data ingestion. Everything happens on demand when a workflow runs an Exchange Online action or a health check fires. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Exchange Online integration. # Exchange (on-prem) Source: https://docs.serval.com/sections/integrations/exchange-onprem Connect on-premises Microsoft Exchange to Serval to automate mailboxes, distribution groups, and other Exchange administration through remote PowerShell. This integration is available by request during preview. Contact your Serval team to enable it for testing. ## About Exchange (on-prem) The Exchange (on-prem) integration connects Serval to an on-premises Microsoft Exchange server - Exchange 2016, Exchange 2019, or Exchange Subscription Edition - using remote PowerShell (PSRP over WinRM) against the server's `/PowerShell` virtual directory (for example, `https://mail.corp.example.com/PowerShell`). It is a **separate integration** from [Exchange Online](/sections/integrations/exchange-online), which targets Microsoft 365 tenants: connecting one does not grant the other. **Authentication:** an approved Active Directory account (username and password) with Exchange management roles. The connection supports Kerberos, Negotiate, NTLM, and Basic authentication. Choose **Kerberos** for a `/PowerShell` virtual directory in Microsoft's default configuration, which accepts Kerberos only; choose Negotiate or NTLM where your Exchange administrators have enabled NTLM on that directory, and Basic only over HTTPS. The Serval worker does not need to be domain-joined for Kerberos: it obtains tickets from your domain controllers with the account's password. **Worker requirements:** an on-prem Exchange server lives on your private network, so this integration requires a **hybrid (self-hosted) Serval worker** with network reach to the server. Serval's cloud workers cannot reach a private-network target. **Data sync:** On-demand only. There is no background sync, entity ingestion, or scheduled polling - each action opens a fresh remote PowerShell session against your server, runs, and disconnects. Operations run as **structured cmdlet pipelines, not free-form scripts**. The Exchange remote PowerShell endpoint is a NoLanguage constrained runspace - it only accepts Exchange cmdlet invocations, so arbitrary PowerShell script text (variables, loops, expressions) is rejected by the server itself. ## Set up the account Choose an Active Directory identity your organization approves for automation. A dedicated service account is optional; a named account can also authenticate. Grant only the management roles your workflows need. Add the account to the Exchange role group(s) that cover the operations your workflows need - **Recipient Management** covers common mailbox and distribution-group administration. Use the Exchange admin center (**Permissions → Admin roles**) or the Exchange Management Shell: ```powershell theme={null} Add-RoleGroupMember -Identity "Recipient Management" -Member "svc-serval" ``` The account must also have remote PowerShell access enabled. Verify `RemotePowerShellEnabled` with `Get-User -Identity "svc-serval" | Format-List RemotePowerShellEnabled`. From a domain-joined machine, confirm the account can open a session against the endpoint before involving Serval, using the same server name and authentication method the Serval connection will use: ```powershell theme={null} $cred = Get-Credential # enter the approved account credentials New-PSSession -ConfigurationName Microsoft.Exchange ` -ConnectionUri https://mail.corp.example.com/PowerShell ` -Authentication Kerberos -Credential $cred ``` If this fails, fix the account, roles, or endpoint configuration first. Use `-Authentication Negotiate` only when the connection will use Negotiate or NTLM: a Windows client's Negotiate can pick Kerberos, so it does not prove that NTLM is enabled on the endpoint. Run the Serval connection healthchecks from the intended worker as well. ## Prepare for Kerberos authentication Review these items with your directory and network teams before connecting with Kerberos. They apply in addition to the account setup above. * **Network**: TCP port 88 (or the port you give in the KDC list) from the Serval worker's egress addresses to the domain controllers you list as KDCs, or to any the DNS SRV records return, and TCP 80 or 443 to the Exchange server named in the Server URI. * **Time**: the worker nodes' clocks within five minutes of the domain controllers, the Kerberos default tolerance. * **Account keys**: AES encryption types enabled on the account (`msDS-SupportedEncryptionTypes`), with a password set after AES was enabled. Windows updates from 2026 turn off RC4 for Kerberos ticket issuance by default. * **Service principal**: a Kerberos ticket names the host in the Server URI. An Exchange server's own fully qualified name works by default, because its `HTTP/` name maps to the computer account. A load-balanced name such as `mail.corp.example.com` needs an alternate service account credential carrying `http/mail.corp.example.com` (Microsoft: "Configure Kerberos authentication for load-balanced Client Access services"); otherwise point the Server URI at one server's fully qualified name. * **Certificate for a per-server target over HTTPS**: the server's certificate must include the server's own name. If it covers only the load-balanced name, use `http://` with Kerberos message encryption (Microsoft's documented form, TCP 80) instead of skipping certificate verification. * **Extended Protection**: Microsoft sets Extended Protection to Off on the front-end `/PowerShell` virtual directory. Serval sends channel bindings with its Kerberos tokens over HTTPS; if your administrators enabled Extended Protection there, a load balancer that terminates TLS with a different certificate than the server will make Kerberos fail. The Serval worker keeps the Kerberos ticket in memory for the life of a single command run and writes no ticket or keytab to disk. The Kerberos configuration for the run is a small file (the realm and the KDC list) in a private temporary directory that the worker removes when the run ends; a removal that fails is logged rather than failing the run. Each run obtains one ticket-granting ticket with the account's password, so a wrong password costs one logon per run, not one per request. ## Connect in Serval In Serval, open the Exchange (on-prem) integration and start a new connection. * **Server URI** (required) - the URL of your Exchange server's PowerShell virtual directory, e.g. `https://mail.corp.example.com/PowerShell`. Must be an `http://` or `https://` URL. With Kerberos, `http://` is acceptable because the session is encrypted with the Kerberos session key, the form Microsoft documents for remote Exchange PowerShell; Basic requires `https://`. Enter the final PowerShell URL: a Kerberos connection does not follow redirects. * **Username** (required) - the approved account, as `CORP\svc-serval` or `svc-serval@corp.example.com`. For Kerberos, the UPN form carries its own realm; the `CORP\svc-serval` form needs the Kerberos Realm field. * **Password** (required) - the account's password. * **Negotiate (NTLM)** - the default; authenticates with NTLM, so NTLM must be enabled on the `/PowerShell` virtual directory. * **NTLM** - force NTLM explicitly. * **Basic (requires HTTPS)** - sends credentials directly; Serval refuses Basic over plain `http://` because the credentials would travel unencrypted. * **Kerberos** - authenticates with a Kerberos ticket obtained from your domain controllers with the account's password. Choose it for a `/PowerShell` virtual directory in Microsoft's default configuration. Selecting it shows two more fields, described in the next step. * **Kerberos Realm** - your Active Directory Kerberos realm in upper case, for example `CORP.EXAMPLE.COM`. Required when the username is `CORP\svc-serval` or `svc-serval`; optional for `svc-serval@corp.example.com`, where it defaults to the upper-cased suffix. * **Kerberos KDCs (Optional)** - comma-separated domain controllers, each a host name or IPv4 address with an optional `:port` (default 88), up to 16. Leave blank to discover them through DNS SRV records (`_kerberos._tcp.corp.example.com`), which requires the worker's DNS resolver to serve your domain. The service principal Serval asks for is always `HTTP/` followed by the Server URI host, so the Server URI must name a host that holds that principal; an Exchange server's own fully qualified name does by default. The endpoint must answer an unauthenticated request with a `401` Kerberos challenge; Serval refuses an endpoint that answers without challenging, because no Kerberos exchange would have taken place. **Instance Name (Optional)** - a friendly name for this connection. If left blank, the connection is named after the server's host name. **Skip TLS certificate verification** is available for servers with self-signed certificates. It weakens transport security - prefer mounting a PEM CA bundle and setting `REQUESTS_CA_BUNDLE` in the worker environment while leaving verification on. The connection healthchecks query `Get-Recipient`, `Get-Mailbox`, and `Get-DistributionGroup` with a one-item limit. The account needs these read cmdlets in its role assignments; the connection check does not require organization configuration permissions. ## SecureString parameters Commands such as `New-RemoteMailbox` require a PowerShell `SecureString` for their password parameter. Use `microsoft.powershell.exchangeOnPrem.secureString(value)` as the parameter value in a structured pipeline. The runner negotiates a PSRP session key and encrypts this value in the protocol's SecureString format. The wrapper selects a wire type; it does not make workflow inputs secret or prevent them from being persisted. Do not put passwords directly in workflow source or assume this wrapper redacts them from workflow history. Use your approved workflow secret-handling mechanism. The password for a new AD user is separate from the credentials used to connect to Exchange. ## Operation results Typed actions fail when Exchange reports an error, including non-terminating PowerShell errors. The raw pipeline action returns `errors` and `hadErrors`; check both before using its output. Runner output is limited to 32 MiB; narrow large queries or select fewer properties. A timeout or an error does not roll back changes already applied on the Exchange server. Check the current state before retrying a write. `getDistributionGroup` reads group metadata without enumerating members. Use `getDistributionGroupMembers` when you need the membership list. Group writes normally require the account to be listed in the group's `ManagedBy` owners. For an approved non-owner administrator, set `bypassSecurityGroupManagerCheck: true` on the update, delete, add-member, or remove-member action. Exchange still requires the **Security Group Creation and Membership** role and the applicable recipient scope; this option does not bypass RBAC. Group notes (including the `description` alias) are updated through `Set-Group`. When you also update mail settings, the helper issues separate commands; they are not atomic. ## Gotchas and troubleshooting The server rejected the credentials or the account lacks remote PowerShell access. Verify the username and password, confirm the account has the required Exchange roles and `RemotePowerShellEnabled` is enabled, and check that the chosen authentication method is enabled on the PowerShell virtual directory in IIS. If the directory offers only Kerberos (Microsoft's default for the front-end `/PowerShell` directory), switch the Authentication Method to **Kerberos**. With Kerberos, a `401` after a ticket was issued usually means the server could not accept the ticket: check that the service principal for the Server URI host belongs to the account the server uses, or point the Server URI at one server's fully qualified name. Some endpoints, often a load-balanced name, answer `403` to an unauthenticated request and never send a `WWW-Authenticate` challenge, so the connection fails before any credential is sent. With **Kerberos**, the error says which side of the Kerberos token the `403` fell on. "Before any Kerberos token was sent" means the endpoint never challenged: point the Server URI at an individual Exchange server that challenges, typically the server's own fully qualified name, and ask your Exchange administrator which server names accept Kerberos for remote PowerShell. "After the Kerberos token was sent" means the endpoint refused the authenticated account: check remote PowerShell access and role membership. The connection healthcheck reports "Kerberos authentication failed" with a short hint when it recognizes the message, followed by the Kerberos library's own text. The library text often includes the account or service principal it was working on and ends with a numeric code: | Message | What to check | | - | - | | Cannot contact any KDC | Network path from the worker to the KDCs on TCP port 88 or the port you listed; the KDC list in the connection settings | | Cannot find KDC for realm | No KDC list and DNS discovery found none: fill in the KDC list or check the worker's DNS | | Clock skew too great | Time synchronization on the worker nodes | | Server HTTP/host\@REALM not found in Kerberos database | The host in the Server URI has no service principal: point the Server URI at one server's fully qualified name; a load-balanced name needs a service principal your Exchange administrators register for it | | Server krbtgt/DOMAIN\@REALM not found in Kerberos database | The Server URI host is outside your realm's DNS domain; use a server name under it | | Preauthentication failed, or Decrypt integrity check failed | The password in the connection settings | | Client 'user\@REALM' not found in Kerberos database | The username and the Kerberos realm | | Password has expired | Set a new password and update the connection | | KDC policy rejects request | The account's authentication policy or silo, with your identity team | | KDC has no support for encryption type | AES keys on the account | | Failed to authenticate the user user\@REALM with kerberos | The server did not accept the ticket: the service principal for the Server URI host, or point the Server URI at one server's fully qualified name (see the 401 entry above) | | The endpoint answered (status) without a Kerberos challenge | The endpoint accepted the request before any Kerberos exchange, so Serval refused the session; confirm the Server URI is the Exchange PowerShell directory and that the directory requires Kerberos | | The server accepted the Kerberos token without completing mutual authentication | The server answered without the token that proves its identity, so Serval refused the session; review the endpoint's Kerberos configuration with your Exchange administrator | | Code: 403 ... the endpoint answered 403 before any Kerberos token was sent | The endpoint never challenged (see the 403 entry above) | | Code: 403 ... the endpoint answered 403 after the Kerberos token was sent | The endpoint refused the authenticated account: remote PowerShell access and role membership (see the 403 entry above) | | The endpoint redirected (status) to (URL); a Kerberos token is bound to the URL it was issued for | Enter the final PowerShell URL as the Server URI; a Kerberos connection does not follow redirects | | Kerberos realm is required unless the username is a UPN | Fill in **Kerberos Realm**, or use the account's UPN as the username | | Kerberos username must be `user@corp.example.com`, `DOMAIN\user` or a bare account name without spaces | Enter the username in one of those three forms | | Kerberos libraries are not available in this worker image | Upgrade the self-hosted worker to a release that includes Kerberos support | | Exchange on-prem integration has an invalid connection configuration (with Kerberos selected) | The self-hosted worker predates Kerberos support; upgrade it before using this method | The worker can't reach the server. The hybrid worker needs network egress to the Exchange server's host and port - check firewalls and routing, and make sure the worker's Kubernetes NetworkPolicy allows egress to your private CIDR ranges (cluster policies often allow only public internet egress by default). With Kerberos, the worker also needs TCP port 88 to the domain controllers; a blocked port, or a controller that accepts the connection but never answers, shows as "Cannot contact any KDC" within about 20 seconds of the unanswered request. A run the worker had to stop at its deadline names the last step it reached (reading the payload, the Kerberos logon, the WSMan connection, the runspace, the pipeline) in the error details. The Exchange server presents a certificate the worker doesn't trust - typically a self-signed or internal-CA certificate. Mount a PEM CA bundle in the worker and set `REQUESTS_CA_BUNDLE` to its path, or enable **Skip TLS certificate verification** on the connection if you accept the weaker transport security. For a Kerberos connection to an individual server whose certificate names only the load-balanced address, prefer `http://` with Kerberos message encryption over skipping verification. The Exchange remote endpoint is a NoLanguage constrained runspace: it accepts Exchange cmdlet invocations with parameters, but no script syntax (variables, loops, expressions). Serval sends operations as structured cmdlet pipelines for this reason - compose multiple cmdlets rather than writing a script. This integration targets your on-premises servers over PSRP/WinRM; [Exchange Online](/sections/integrations/exchange-online) targets Microsoft 365 with an Entra app registration. In hybrid organizations, on-prem-synced recipients must be changed on-prem - cloud writes to synced objects fail. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Exchange (on-prem) integration. # Factorial Source: https://docs.serval.com/sections/integrations/factorial Connect Factorial HR to Serval with a company API key to give workflows secure, on-demand access to employees, time off, recruiting, payroll, and the rest of the Factorial API. ## About Factorial Factorial is an HRIS for small and mid-sized companies that covers the employee lifecycle: onboarding, time off, attendance, payroll, recruiting (ATS), documents, and reporting. Serval connects to Factorial using a company-scoped API key stored encrypted by Serval, and your workflows get typed, proxied access to the full Factorial REST API (version 2026-04-01). Workflow code never sees the raw key - Serval injects it on every request. This integration is currently in **Beta** and shows a Beta badge in the Serval app. **Authentication:** API key, sent by Serval as the x-api-key header on every request to Factorial. **Data sync:** On-demand only. There is no background sync, entity ingestion, or pre-installed workflows - workflows call Factorial at the moment they need data. ## What the Factorial integration enables | Capability | Description | | - | - | | Factorial API request action | Gives workflows typed access to the Factorial REST API (version 2026-04-01) - 382 endpoints across 37 areas, including employees, teams, time off, attendance, recruiting (candidates, applications, job postings), contracts, payroll, documents, custom fields and custom resources, expenses, finance, holidays, IT management, locations, performance, project management, shifts, tasks, time planning, trainings, work schedules, and webhook subscriptions. | | Connection health checks | Three built-in checks verify the API key works and can read your Employees and Teams data. | | API context for Serval AI | The full Factorial API surface is indexed as "Factorial v2026-04-01 API", so AI-assisted workflow authoring can discover and call Factorial endpoints for you. | Anything defined in the [Factorial API](https://apidoc.factorialhr.com/reference/getting-started) can be accessed through Serval. ## Get your credentials Serval needs a Factorial API key created by a **company admin**. Keys are scoped to your whole company (not to an individual user) and carry admin-level access, so treat the key like a service-account credential. Factorial's official guide is here: [How to create API keys in Factorial](https://help.factorialhr.com/en_US/how-to-create-api-keys). The key inherits admin-level, company-wide access, so it must be created from an admin account. If you don't see this area, ask a Factorial administrator to grant you the right access. Use a descriptive name such as "Serval Integration" so it is easy to identify later. Factorial shows the key only once. If you lose it, revoke it and issue a new one. Copy the key as soon as it is created - Factorial will not show it again. Connecting a Factorial **demo** or non-default region tenant? Note its API host (for example, api.eu2.demo.factorial.dev) - you will enter it in the optional API URL field in Serval. Production tenants can skip this entirely. ## Connect in Serval Find Factorial in the integrations list (it carries a Beta badge) and start a new connection. Paste the key you copied from Factorial. The field's helper text reads: "Generated in Factorial → Settings → Advanced configuration → API Keys by a company admin. Sent as the x-api-key header." The placeholder shows api.factorialhr.com, which is used automatically when the field is blank. The helper text explains that production tenants should leave it blank and that it is only needed when connecting a Factorial demo or non-default region tenant (for example, api.eu2.demo.factorial.dev). You can paste a full URL from Factorial's docs - Serval trims it down to just the host. Serval stores the key encrypted and normalizes the API URL to a bare host. Editing the connection later is safe: the saved key appears as a locked, masked value - bullets plus its last 4 characters - with a control to replace it (a **Replace** button on the reconnect form, a pencil icon on the connection settings page). Leave it untouched to keep the existing key; even submitting an empty replacement keeps the existing key. The API URL field comes pre-filled with the saved host, and clearing it keeps that host rather than resetting anything. ## Verifying the connection The integration ships with three health checks you can run from the connection page: | Health check | What it does | On success | On failure | | - | - | - | - | | Test Factorial Connection | Verifies Serval can reach Factorial and that the API key is accepted, by reading the key's own public credentials. | "Successfully connected to Factorial and verified the API key." | "Unable to connect to Factorial. Please verify your API key is valid and was generated by an admin user." | | List Factorial Employees | Lists active employees and reports the count. | "Successfully listed employees from Factorial (count: \[number])." | "Unable to list employees from Factorial. Please verify the API key has admin access to the Employees resource." | | List Factorial Teams | Lists teams and reports the count. | "Successfully listed teams from Factorial (count: \[number])." | "Unable to list teams from Factorial. Please verify the API key has admin access to the Teams resource." | If "Test Factorial Connection" passes but the Employees or Teams checks fail, your key is valid but lacks admin access to those resources. Re-issue the key from a company admin account in Factorial and update the connection. ## Gotchas and troubleshooting Factorial API keys are company-scoped, not user-scoped, and the health checks require admin access to the Employees and Teams resources. If the connection test fails with a message about the key being "valid and generated by an admin user", have a company admin create the key. Because the key grants company-wide access, treat it like a service-account credential. Serval only sends your key to official Factorial API hosts - production (api.factorialhr.com) and Factorial demo/dev hosts (for example, api.eu2.demo.factorial.dev). Demo and production are separate environments, so always pair the key with the matching tenant's host: a production key will not authenticate against a demo API URL. Requests to any other host never receive your key. Serval reduces whatever you paste to a bare host: it trims whitespace, lowercases, strips any leading http\:// or https\://, and drops any path (including a full base URL copied from Factorial's API docs). On a new connection, leaving the field blank - or pasting something that reduces to nothing, like a bare scheme - selects the production host api.factorialhr.com. If a connection points at the wrong tenant, check what host the field resolved to. The typed action surface and the AI's knowledge of Factorial endpoints are generated from Factorial's 2026-04-01 API specification. Endpoints that only exist in other Factorial API versions are not part of the typed surface. On the edit form, the saved key shows as bullets plus its last 4 characters; submitting without replacing it keeps the existing key, and even an empty replacement keeps the existing key. The API URL field is pre-filled with the saved host, and a cleared or whitespace-only API URL keeps that host rather than resetting to the production default - so to move a connection from a demo host back to production, type api.factorialhr.com explicitly. Nothing is silently cleared - only values you actually replace are changed. Factorial shows a Beta badge in the Serval app. Functionality is fully usable, but surfaces may evolve. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Factorial integration. # Figma Source: https://docs.serval.com/sections/integrations/figma Connect Figma to Serval with your own Figma OAuth app (tokens refresh automatically) or a personal access token, so workflows can read design files, manage comments and webhooks, and call anything in the Figma REST API. ## About Figma Figma is a collaborative interface-design platform for design files, prototyping, and design systems. Serval connects to Figma in one of two ways: with a **Figma OAuth app that you own** (recommended), where Serval refreshes the access token itself so nothing expires, or with a **personal access token** that you paste in and rotate by hand. Either way the connection acts as the Figma user who authorized it, limited by the scopes granted, and Serval only ever sends credentials to one host: api.figma.com. **Authentication:** Your own Figma OAuth app (authorization code with automatic refresh), or a personal access token (API key). **Data sync:** On-demand only. There is no background sync, resource import, or scheduled polling - Serval calls Figma only when a workflow or health check runs. ## What the Figma integration enables | Capability | Description | | - | - | | Read files, nodes, and versions | Fetch a design file's full contents, specific layers within it, file metadata, and version history. | | Render images and fetch image fills | Generate image renders of file contents (render links expire after 30 days) and retrieve download links for images used as fills (those links expire within 14 days). | | Manage comments and reactions | List, post, and delete comments on files, and view, add, or remove emoji reactions on them. | | Browse teams and projects | List a team's projects and the files inside a project. | | Inspect components and styles | Read published components, component sets, and styles at the team, file, or individual level. | | Read and modify variables | Read a file's local and published design variables, and create, update, or delete them (Figma makes variables available to full members of Enterprise organizations). | | Manage webhooks | List, create, update, and delete webhooks - including a team's webhooks - and inspect recent webhook deliveries. | | Manage dev resources | Read, create, update, and delete a file's dev resources. | | Pull library analytics | Read action and usage analytics for a library's components, styles, and variables. | | Read activity logs and payments | Read organization activity logs (Figma reserves these for organization administrators) and payment information for plugins, widgets, and Community files you own. | | Identity check | Look up which Figma user the connection acts as - also what the built-in health check does. | Anything defined in the [Figma API](https://www.figma.com/developers/api) can be accessed through Serval. ## Get your credentials Figma limits personal access tokens to 90 days. An OAuth app that you own gives Serval a refresh token instead, so the connection renews itself. Do this once, signed in to Figma as a **team admin with a Full or Dev seat** - the connection acts as that user, and Figma throttles View seats to a handful of API calls per month. Many teams use a shared IT account here so the connection survives staff changes. Open [Figma developer apps](https://www.figma.com/developers/apps) and create a new app with your team as the owner. Figma shows the **Client ID** and **Client secret** once, right after creation: copy both into your password manager now. Open the Figma connect dialog in Serval, choose **Connect with your Figma OAuth app**, and copy the **Callback URL** it shows. Paste it into the app's OAuth 2.0 redirect URLs. Figma requires an exact match, so copy it rather than retyping it. In the app's configuration flow, on the OAuth scopes page, select every scope you plan to request in Serval, then publish the app as **Private**. Serval always requests `current_user:read` (it names the connection and powers the health check); the defaults also cover file contents, metadata, versions, comments, dev resources, folders (Figma's new name for projects), libraries, and webhooks. Leave the Enterprise-only scopes (variables, library analytics, and the org scopes) off unless your plan includes them - Figma rejects them at consent otherwise. Scopes you add later take effect only after you publish the app again. Private apps serve your own team without a Figma review. Don't leave the app in Draft: a Draft app can't call the REST API, and a published version without the scopes you selected fails at consent with "Invalid scopes for app". A personal access token carries the access of the Figma user who creates it, narrowed by the scopes chosen at creation, and Figma caps its lifetime at 90 days. Figma's guide: [Manage personal access tokens](https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens). In Figma, open **Settings**, then the **Security** tab, then **Personal access tokens**. Generate a token named for Serval, grant the scopes your workflows need, and pick the longest expiration Figma offers. Note the date: when it lapses, workflows fail until you paste a new token (or switch the connection to an OAuth app). Figma shows the token only once. ## Connect in Serval Add a new Figma connection from your Serval integrations page. The connect dialog offers two options. 1. Copy the **Callback URL** into your Figma app if you haven't already. 2. Enter an optional **Display name** (defaults to `Figma ()` with the authorizing user's email), the **Client ID**, and the **Client secret**. 3. Tick the **scopes** Serval may request. `current_user:read` is always included. Every selected scope must also be enabled on your Figma app. 4. Click **Connect Figma** and approve the request on Figma's consent screen. You have 10 minutes from clicking Connect; after that the attempt fails with "Invalid or expired OAuth state" and you resubmit. On success Serval stores the tokens encrypted and refreshes the access token automatically before it expires. Enter an optional **Instance Name** and the **Personal Access Token**, then click **Connect**. Serval stores the token encrypted and sends it as `X-Figma-Token` on every call. **Switching an existing token connection to the OAuth app:** open the connection and click **Reconnect**, then choose **Connect with your Figma OAuth app**. The connection is converted in place - its roles, policies, and workflow bindings stay - and the old token is discarded. The reverse isn't offered: an OAuth-app connection can't be switched back to a token without deleting it. When you reconnect an OAuth-app connection, the Display name, Client ID, and scopes are pre-filled from the existing setup. The Client secret is never stored where the dialog can read it, so re-enter it (or regenerate it in Figma if it's lost). ## Verifying the connection Figma connections include the built-in health check **Test Figma Connection**, which asks Figma which user the connection acts as. It runs automatically when you connect and can be run again from the connection's page; when Health Alerts are enabled it also runs on the daily schedule. * Success: `Successfully connected to Figma as ""`. * Failure: `Unable to connect to Figma. The access token may have expired or been revoked, or the OAuth app may have been unpublished; reconnect the integration.` A passing check proves the credential is valid. If a workflow still fails on a specific file, project, or team, the authorizing Figma user can't see that resource, or the call needs a scope or Figma plan the connection doesn't have. ## Gotchas and troubleshooting Every time a user authorizes your Figma app, or Serval refreshes the token, Figma invalidates that user's previous access token for the same app. Connect Figma once per authorizing user per Figma app; if a second Serval team needs its own connection, create a second Figma app or authorize with a different account. Never point a staging or test environment at the app a production connection uses. The connection acts as the authorizing user and inherits that user's seat. Team webhooks require a team admin, and Figma limits View seats and other non-editor seats to a few file reads per month, so authorize as a team admin with a Full or Dev seat. If that person leaves the team, the tokens stop working and the connection must be reconnected by someone else. Three causes cover almost every case: the Callback URL registered on the Figma app doesn't match Serval's exactly (copy it from the dialog), a selected scope isn't enabled on the published version of the app (Figma answers "Invalid scopes for app" and scope changes only take effect after you publish the app again), or the app is still in Draft. Figma's authorization codes also expire 30 seconds after issue, so finish the consent screen promptly. Serval expects a Private app. Figma blocks Public apps from the team projects and project files endpoints and puts them through a review queue, so publishing the app as Public removes "Browse teams and projects" from the connection. For a token connection, the token has expired (90-day cap) or was revoked: reconnect with a new token, or switch to an OAuth app. For an OAuth-app connection, the app was unpublished, its secret rotated, or the authorizing user lost access: reconnect. Serval passes Figma's error text through where it has one. These areas are gated by Figma, not Serval: variables need Enterprise, activity logs need an organization admin on Enterprise, payments only cover plugins, widgets, and Community files you own. Nothing on the Serval side changes this. Figma identifies files by a **file key**, the string right after "file/" or "design/" in the file's web address, not the full URL. Node, team, and project IDs are separate values. For access-token connections Serval derives an internal identifier from the Instance name once, at creation. Two token connections on the same team with the same name (or both left blank) resolve to the same connection, so give each a distinct name; leaving the name blank when rotating a token keeps the existing one. OAuth-app connections are keyed on the authorizing Figma user instead. Figma tracks limits per authorizing user, per app, and per the plan of the file being read. Files kept in drafts or a free space get Starter limits with multi-day retry windows; keep the files your workflows touch inside the paid team. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Figma integration. # Firstbase Source: https://docs.serval.com/sections/integrations/firstbase Connect Firstbase to Serval with an API key so workflows can manage device orders, inventory, returns, ITAD, and SCIM user provisioning. ## About Firstbase Firstbase is an IT equipment lifecycle platform covering device ordering and catalog, inventory tracking, shipments, returns and replacements, IT asset disposition (ITAD), and SCIM user provisioning for onboarding and offboarding. Serval connects to Firstbase with a single API key and gives your workflows full access to the Firstbase public API, including its SCIM provisioning endpoints. **Authentication:** API key **Data sync:** On-demand only. Nothing is imported from Firstbase on a schedule - workflows read and write Firstbase data live, and three health checks run automatically right after you connect to confirm the key works. ## What the Firstbase integration enables | Capability | Description | | - | - | | SCIM user provisioning | List, look up, create, update, and remove users, plus bulk operations and CSV bulk upload. Removing a user is a soft delete that starts the Firstbase offboarding process. | | Inventory and asset tracking | List all inventory and get asset details with rich filters (person, warehouse, deployment status, SKU, search text, date ranges); add and remove inventory tags; manage inventory levels. | | Equipment orders | List and create orders, look up a specific order, and approve or decline orders awaiting approval. Orders can ship to a person or an office. | | Returns and replacements | Create and track return orders with return-kit shipping, office returns, and optional address confirmation; create replacements that pair a return with a new equipment order. | | Shipments and shipment notices | List shipments; create and track inbound shipment notices from a supplier or office; create inventory orders that send equipment to a warehouse. | | Catalog and packages | Read your organization's catalog SKUs and equipment packages. | | ITAD (IT asset disposition) | List eligible ITAD assets, create disposition requests (automatically grouped into one request per warehouse), and track request status including resale values and certificates of destruction. | | New joiners and people emails | List new joiners with stats and filters, send new-joiner reminder emails, and trigger admin emails per person (resend activation, resend offboarding, send a platform invite). | | Logistics reference data | Read the warehouses, regions, and offices configured for your organization. | Anything defined in the [Firstbase API](https://apipub.firstbasehq.com/swagger-ui/index.html) can be accessed through Serval. ## Get your credentials You need a Firstbase API token created by an **Admin** user in the [Firstbase admin app](https://app.firstbasehq.com/). Go to [app.firstbasehq.com](https://app.firstbasehq.com/) and sign in with an Admin account. Only Admin users can create API tokens. Open the **Settings** menu in the top navigation bar and select **Firstbase API**. Create a new token and give it a recognizable name, for example "Serval Integration". Copy the token - you will paste it into Serval in the next section. To rotate the key later, create a new token in the Firstbase app, enter it in Serval's connection settings (use the pencil icon next to the masked key), and then delete the old token in Firstbase. ## Connect in Serval Find **Firstbase** in the integrations catalog and start the connection. Fill in the one field on the form, **API Key** (required, shown as "API Key \*"). The helper text reads: "Your Firstbase API key. You can generate one from your Firstbase account settings." The input is masked as you type, and the form will not submit while the field is empty. Serval stores the key and pins the connection to a single instance named "Firstbase". If saving fails, you will see "Failed to connect service" or "Failed to install integration" - double-check that you pasted the complete token. Immediately after a successful connect, Serval automatically runs the integration's three health checks so your key is verified right away. When you later open the connection settings, the saved key is shown masked as bullet characters plus its last 4 characters, and the masked value is read-only. You never need to re-enter the existing key: to rotate it, click the pencil icon (or the **Replace** button on the reconnect form), paste the full new key into the "Enter new value" box, and save. If you clear the box and save without entering a new key, the existing key is kept. After a successful update Serval re-runs the health checks automatically; if the update fails, you will see "Failed to update configuration" on the settings page or "Failed to update integration" on the reconnect form. ## Verifying the connection Serval runs three health checks for Firstbase - automatically after you connect or update the key, and on demand from the connection's health panel using the **Run** button. Each one makes a minimal read request to prove the key works: * **Test Firstbase List Packages** - reads a single entry from your equipment packages list. Success: "Successfully connected to Firstbase and retrieved packages list". Failure: "Failed to connect to Firstbase or list packages. Please check your API key and permissions." * **Test Firstbase List Inventory** - reads a single entry from your inventory. Success: "Successfully connected to Firstbase and retrieved inventory list". Failure: "Failed to connect to Firstbase or list inventory. Please check your API key and permissions." * **Test Firstbase List Users (SCIM)** - reads a single user through Firstbase's SCIM provisioning interface. Success: "Successfully connected to Firstbase and retrieved users via SCIM". Failure: "Failed to connect to Firstbase or list users. Please check your API key and permissions." If the packages and inventory checks pass but the SCIM users check fails, your key can read equipment data but not people data. Recreate the token while signed in as a Firstbase Admin and reconnect. ## Gotchas and troubleshooting The most common causes are an incomplete paste of the token or a token created by a non-Admin user. Create a fresh token as an Admin under Settings > Firstbase API, paste the complete value into Serval, save, and re-run the health checks. Failure messages all end with "Please check your API key and permissions." This integration has no scheduled sync - nothing is imported from Firstbase in the background, and there are no prebuilt sync workflows. All data access happens live when a workflow runs, so any dashboard or entity built on Firstbase data needs a workflow to fetch it. Deleting a user through the SCIM provisioning capability is a soft delete that kicks off the Firstbase offboarding process - the person keeps Firstbase platform access until offboarding completes. Relatedly, the OFFBOARDING return reason cannot be set when creating returns through the API. Firstbase expects the credential in an Authorization header using the "ApiKey" scheme, which Serval applies for you on every request. If your team tests the key manually with another tool, a standard "Bearer" header will be rejected by Firstbase even though the key itself is valid. The connection is always pinned to Firstbase's public API service at apipub.firstbasehq.com, with the instance display name "Firstbase". Your key is only ever sent to that host, and no instance URL needs to be (or can be) configured. Endpoint coverage tracks the Firstbase public API specification and may change as that specification evolves. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Firstbase integration. # Fleet Source: https://docs.serval.com/sections/integrations/fleetdm Connect Fleet (FleetDM) device management to Serval to look up, lock, wipe, and audit company devices through workflows and the full Fleet API. ## About Fleet Fleet (FleetDM) is an open-source device management (MDM) and osquery platform. Serval connects to either Fleet cloud or a self-hosted Fleet server using an API token, then lets your team run device workflows - look up a user's laptop, lock or wipe a lost device, recover a disk encryption key, audit installed software - and reach the rest of the Fleet API on demand. The integration appears as **Fleet** in the Serval app. **Authentication:** API token (Bearer). Serval stores your Fleet domain and API token and attaches the token to every request on its own servers - the token never reaches workflow code. **Data sync:** On-demand only. There is no background sync and no data ingestion; Serval calls your Fleet instance at the moment a workflow or API action runs. ## What the Fleet integration enables | Capability | Description | | - | - | | Full Fleet REST API access | A typed API action covering 156 Fleet API endpoints (203 operations): hosts, queries, policies, scripts, software, teams, users, MDM commands (lock, unlock, wipe), configuration profiles, vulnerabilities, labels, and activities. Works with Fleet cloud and self-hosted instances. | | Device Management bundle | An installable bundle of six of the workflows below: "Lock, wipe, and retrieve information about Fleet-managed devices." It includes the lock, wipe, disk encryption key, host software, active workstation, and computers-for-user workflows. | | List Fleet DM Computers for User | Retrieves all hosts associated with a user's email address, paging through the full list automatically. No approval required by default. | | Get User Active Fleet Workstation | Returns the most recently active workstation (non-mobile device) for a user. No approval required by default. | | Run Fleet DM Query on User Workstations | Runs a Fleet query (by query ID) live against a user's workstation hosts - mobile devices are excluded - and returns per-host results plus an AI-generated summary of the data. No approval required by default. | | Lock Fleet DM Host | Finds the user's most recently seen workstation and sends a remote lock command - useful for lost or stolen laptops. Also requests the unlock PIN, which Fleet provides for macOS hosts. Requires installer approval by default. | | Wipe Fleet DM Host | Finds the user's most recently seen workstation and sends a remote wipe command; the device is wiped once it comes online. Requires installer approval by default. | | Get Fleet DM Host Disk Encryption Key | Retrieves the disk encryption recovery key (FileVault or BitLocker) for a user's most recently active workstation. Requires installer approval by default. | | Get Fleet DM Host Software | Lists all installed software on a user's most recently active workstation, for troubleshooting or auditing. No approval required by default. | | List Fleet DM Policies | Lists all global policies in Fleet, including pass/fail host counts, for compliance auditing. No approval required by default. | The endpoints available through Serval mirror the [Fleet REST API](https://fleetdm.com/docs/rest-api/rest-api) - see Fleet's documentation for what each endpoint does. ## Get your credentials You need two things: your Fleet domain and a Fleet API token. The token belongs to a Fleet user account and inherits that account's role, so create it from an account with enough privileges (Admin or Maintainer for some operations). See [Fleet's REST API documentation](https://fleetdm.com/docs/rest-api/rest-api) for details. Sign in to Fleet cloud (for example, yourcompany.cloud.fleetdm.com) or your self-hosted Fleet server. Go to **My account**, then choose **Get API token**. You will not be able to see it again after closing the dialog. This is the address you use to reach Fleet, without any https\:// prefix - for example, yourcompany.cloud.fleetdm.com or fleet.yourcompany.com. Tokens taken from a regular Fleet UI user are session-scoped and can expire when that user logs out. For long-lived automation, Fleet recommends a dedicated API-only user. A token can also be obtained programmatically via Fleet's login API. The token inherits the role of the Fleet user it belongs to. Listing users and policies, sending lock and wipe commands, and retrieving disk encryption keys require elevated roles (Admin or Maintainer) in Fleet. ## Connect in Serval In Serval, find **Fleet** in the integrations list and choose to connect it. Enter the bare domain only - no https\:// prefix and no trailing path. The form shows the example "yourcompany.cloud.fleetdm.com" and the help text "Your Fleet domain (without https\:// or trailing path). For example: yourcompany.cloud.fleetdm.com or fleet.yourcompany.com". Anything that is not a plain domain is rejected with "Enter a valid Fleet domain (e.g., yourcompany.cloud.fleetdm.com or fleet.yourcompany.com)". Leaving it empty shows "This field is required". Paste the token into this password field. The help text reads "Your Fleet API token. You can get this from your user profile in Fleet UI or via the login API." Leaving it empty shows "This field is required". Serval immediately verifies the connection by asking Fleet who the token belongs to. When you edit an existing connection, the form opens pre-filled: the API Domain shows the saved domain, and the API Token appears masked except for its last 4 characters, with a **Replace** button. Leave the token untouched to keep the saved value - only click **Replace** and paste a new token when you want to rotate it. On the Serval side, a blank domain keeps the existing domain and a blank token keeps the existing token. ## Verifying the connection The Fleet connection runs five health checks: * **Get Current User** - confirms Serval can authenticate and identifies the token's user and role. Success: "Successfully authenticated as \[name or email] (\[role])" Failure: "Unable to authenticate with FleetDM. Please check your API token and domain." * **List Hosts** - confirms device listing works and captures a few sample devices. Success: "Successfully listed hosts from FleetDM (\[number] returned)" Failure: "Unable to list hosts from FleetDM. Please check your permissions." * **List Users** - confirms user listing works and captures a few sample users. Success: "Successfully listed users from FleetDM (\[number] returned)" Failure: "Unable to list users from FleetDM. Please check your permissions." * **List Policies** - confirms global policy listing works and captures a few sample policies. Success: "Successfully listed policies from FleetDM (\[number] returned)" Failure: "Unable to list policies from FleetDM. Please check your permissions." * **List Queries** - confirms saved-query listing works and captures a few sample queries. Success: "Successfully listed queries from FleetDM (\[number] returned)" Failure: "Unable to list queries from FleetDM. Please check your permissions." If **Get Current User** passes but **List Users** or **List Policies** fails, your token is valid but the Fleet account behind it does not have a high enough role. Switch to a token from an Admin or Maintainer account - the same applies if lock, wipe, or encryption key workflows fail later. ## Gotchas and troubleshooting The API Domain must be a bare domain - no https\:// prefix and no trailing path. Anything else is rejected with "Enter a valid Fleet domain (e.g., yourcompany.cloud.fleetdm.com or fleet.yourcompany.com)". Both Fleet cloud domains and self-hosted domains are accepted. The API token inherits the role of the Fleet user it belongs to. Listing users and policies, lock and wipe commands, and disk encryption key retrieval need an Admin or Maintainer account in Fleet. Tokens from a regular UI user are also session-scoped and can expire when that user logs out - use a dedicated API-only user for long-lived automation. Lock Fleet DM Host, Wipe Fleet DM Host, and Get Fleet DM Host Disk Encryption Key require approval from the workflow installer by default. The read-only workflows run without approval. Approval settings can be adjusted when installing the bundle. Workflows that target "workstations" (lock, wipe, active workstation lookup, query runs) deliberately exclude mobile devices: any host whose platform is iOS, iPadOS, or Android is filtered out, as is any host with no platform recorded. Devices on every other platform (macOS, Windows, Linux) are treated as workstations. The integration displays as **Fleet** in the Serval app, but its internal identifier is "fleetdm". If a search for one name comes up empty, try the other. It should not - when you edit, the saved domain is pre-filled, an untouched masked token keeps the stored token exactly as it was, and a blank value for either field keeps the existing value. Change only the field you mean to change. If health checks fail after an edit, re-enter the value you changed and save again. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Fleet integration. # FMS:Workplace Source: https://docs.serval.com/sections/integrations/fms-workplace Connect Serval to FMS:Workplace so workflows can read facility data through the FMInteract Web Service SOAP API. ## About FMS:Workplace FMS:Workplace (FM Systems) is a facilities and workplace management platform. The Serval integration connects to your tenant's **FMInteract Web Service** — a SOAP endpoint that exposes permissioned views and stored procedures as data objects. Workflows call a single `getData` action with an object name and type; Serval injects the Web Service username and password into the SOAP body server-side on every request, so workflow code never handles those credentials. **Authentication:** Web Service username and password embedded in the SOAP request body (not an HTTP header). Serval stores them encrypted and splices them into each `GetData` call automatically. **Data sync:** On demand only. There is no background sync — workflows fetch facility data live when they run. ## What the FMS:Workplace integration enables | Capability | Description | | - | - | | FMS:Workplace getData | Call the FMInteract `GetData` SOAP operation with an object name, object type, and optional parameters. Returns tabular rows from views or stored procedures your Web Service user is permissioned to access. | | Typed workflow context | Workflows receive the configured service URL as `apiDomain` on the integration context, so the SDK routes requests to your tenant's `.svc` endpoint. | The objects available to your workflows depend entirely on what your FMS administrator permissioned to the Web Service user — Serval does not ship a fixed catalog of facility views. ## Get your credentials You need three values from your FMS:Workplace administrator: the full Web Service URL, a Web Service username, and its password. Hosted FMS:Workplace instances typically use a path like `yourcompany.fmshosted.com/FMIWebService/FMInteractWebService.svc`. Test and production environments may use different path segments (for example a `TST_FMIWebservices` prefix). Copy the host and path **without** `https://`. In FMS:Workplace, open **System Administration → Modify System Settings → Web Services → Web Services User Setting**. Note the dedicated Web Service user — this is not necessarily the same as an interactive FMS application login. Use the password configured for that Web Service user. Serval stores it encrypted and injects it into the SOAP envelope on every call. Serval's connection test reads the `L0` text view. Ensure the Web Service user is permissioned to that object, or expect the health check to fail even when other views work. Serval's outbound allowlist currently covers `*.fmshosted.com` hosted instances. Self-hosted FMS:Workplace deployments on other domains require an allowlist extension — contact Serval support if your service URL is not on `fmshosted.com`. ## Connect in Serval In Serval, add the FMS:Workplace integration. Enter the full Web Service endpoint host and path, without `https://`. Example: `yourcompany.fmshosted.com/FMIWebService/FMInteractWebService.svc`. Enter the Web Service user from FMS system settings. Enter the Web Service user's password in the password field. Submit the form. Serval runs **Test FMS:Workplace Connection**, which calls `GetData` for the `L0` view. ## Verifying the connection **Test FMS:Workplace Connection** — reads the `L0` (floors) text view through the full SOAP path, including server-side credential injection. * Success: `Successfully connected to FMS:Workplace (L0 returned N row(s)).` * Failure (auth or URL): `Unable to connect to FMS:Workplace. Verify the Service URL, username, and password, and that the user is permissioned to the L0 view in Web Services settings.` * Failure (reachable but denied): `FMS:Workplace reachable but returned a non-success status… Confirm the Web Service user is permissioned to the L0 view.` If the connection test fails but you know the credentials are correct, ask your FMS admin to grant the Web Service user access to the `L0` view — that is the object Serval uses to prove connectivity. ## Gotchas and troubleshooting Paste only the hostname and path. Serval adds TLS when calling the service. The username in FMS interactive login screens may differ from the Web Service user configured under System Administration. Use the value from Web Services User Setting. `getData` succeeds only for object names and types your Web Service user can read. Build workflows against views your administrator documents for the integration account. UserName and Password elements are injected by the Serval proxy after the workflow submits the SOAP template. Workflow code only contains placeholders. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your FMS:Workplace integration. # Freshservice Source: https://docs.serval.com/sections/integrations/freshservice Freshservice is an IT service management (ITSM) platform - Serval connects to your instance to sync tickets and knowledge articles, ingest service catalog items as runnable workflows, and take actions through the Freshservice API. ## About Freshservice Freshservice is an IT service management (ITSM) platform from Freshworks. The Serval Freshservice integration connects to your Freshservice instance using your instance domain and an agent API key. A single connection powers ticket sync, optional real-time ticket webhooks, knowledge base sync, and service catalog ingestion - plus workflow actions for placing catalog requests, uploading attachments, and calling any part of the Freshservice API. **Authentication:** API key (HTTP Basic auth). You provide your Freshservice domain and an agent API key; the key is a long-lived credential that inherits the permissions of the Freshservice agent who generated it. There is no OAuth flow and no token refresh. **Data sync:** Tickets sync via background polling every 30 seconds by default, or in real time via webhooks (enabling webhook sync turns polling off). Knowledge base content syncs on a recurring schedule. Service catalog syncs are triggered manually from the UI. Workflow actions call Freshservice on demand. ## What the Freshservice integration enables | Capability | Description | | - | - | | Ticket sync | Background polling every 30 seconds. Covers tickets, ticket conversations (comments and replies), requesters (including lookup by email), groups, locations, workspaces, status options, and ticket form fields. A resolved or closed ticket's resolution notes are ingested as an internal (private) note, attributed to the note's author from the ticket activity history, or to the current assignee when the author can't be determined (and left unattributed if neither is known). Attachments sync too: files on a reply or note land on that message, and files added to the ticket itself (for example, screenshots included when the ticket was raised) appear as timeline entries at the time they were added, attributed to the requester when they were part of the original submission. | | Real-time ticket webhooks | Three inbound webhooks - one for newly raised tickets, one for ticket field changes, one for new replies and forwards - authenticated with a secret token header. Enabling webhook sync replaces polling. | | Knowledge base sync | Syncs solution categories, folders, subfolders, and articles on a schedule. Accepting a [knowledge suggestion](/sections/documentation/suggestions/overview) also creates or updates articles in Freshservice. | | Service catalog ingestion | Imports your service catalog items as runnable external workflows, including their request form fields and dropdown choices. Deleted and draft items are skipped. Syncs are triggered manually from the UI. | | Catalog item requests | Places a service catalog request on a requester's behalf, with quantity, optional subject, custom form fields, and optional attachments (attached afterward as private, agent-only notes on the resulting service request). | | Attachment upload | Adds a file attachment to a service request. Because the Freshservice API has no direct attachment upload, the file is posted as a note on the ticket (public by default). | | Generic API access | Any Freshservice REST API call, proxied to your instance with authentication injected automatically. | Anything defined in the [Freshservice API](https://api.freshservice.com/) can be accessed through Serval. ## Get your credentials Serval authenticates with an API key that belongs to a Freshservice **agent**. We recommend a dedicated **full-time agent service account** with the **Account Administrator** account-wide role (or a custom role with workspace management permissions - the connection health checks require one of the two) plus a custom workspace role granting ticket view/reply/edit/create permissions in every workspace Serval should sync. See Freshservice's official guide to [finding your API key](https://api.freshservice.com/#authentication). The account must be an **Agent** (not a Requester) and a **Full-time Agent** (not Occasional). The agent must also complete activation - accept the invitation email and set a password - or its API key will not work. In Freshservice, go to **Admin** → hamburger menu (top left) → **Global Settings** → **Agents** (User Management section) → **New Agent**. Set a descriptive name and email, and set **Agent Type = Full-time Agent**. On the agent's profile → **Permissions** → **Add admin role** (account-wide), select **Account Administrator** → **Save**. The connection health checks expect the key's user to have this role (or a custom role with workspace management permissions) to list your workspaces. Go to **Admin** → **Global Settings** → **Roles** → **New role** (e.g. "Serval Supervisor") with at minimum: View tickets; Send reply to a ticket; Forward a conversation; Edit everyone's notes; Delete a conversation; Merge / split a ticket; Edit ticket properties; Move tickets; Create and Edit Tasks in Tickets (allow reordering); Delete a ticket; Export Tickets. On the agent's **Workspace permissions** → **Add to workspace** → **Add role** → select the custom role "across the workspace". Repeat for every workspace Serval should sync; for restricted groups, also add the agent to the group itself. Accept the invitation email and set a password, then sign in as the agent → **Profile Settings** (top-right avatar) → **API Settings** → ensure the API key is enabled and copy it. Name this agent **Serval**. The API key authenticates as this Freshservice agent, so Serval's AI replies and any tickets it automatically assigns appear under this agent's name in Freshservice. A dedicated, clearly named agent keeps Serval's activity easy to recognize. Serval's connection health checks expect the key's user to have the **Account Administrator** role (or a custom role with workspace management permissions) and membership in **at least one workspace**. The API key inherits exactly the permissions of the agent it belongs to - nothing more. ## Connect in Serval The connect form has exactly two fields: **Domain** and **API Key**. The field asks for "Your Freshservice domain (without https\://, e.g., company.freshservice.com)". Enter the bare domain - Serval normalizes the value by trimming whitespace and stripping any leading "http\://" or "https\://" and trailing slashes. Leaving it empty fails with: "API domain is required". A password-type field described as "API key generated in Freshservice Admin settings". Paste the agent API key you copied above. Leaving it empty on first connect fails with: "API key is required". Submit the form. Serval stores the API key encrypted and uses your domain as the base for every request to Freshservice. The webhook token is **not** on the connect form. Serval generates it automatically and displays it as the read-only **"Authentication Token"** on the integration's ticket sync settings page, alongside the **"Ticket Create Webhook URL"**, **"Ticket Update Webhook URL"**, and **"New Reply Webhook URL"** copy fields and the name of the header to send it in. You only need it if you set up real-time ticket webhooks. When **updating** an existing connection, blank fields keep their previously stored values. You can rotate just the API key without re-entering the domain - and vice versa. The stored webhook token is preserved too. ## Verifying the connection Serval runs three health checks after you connect: **Validate Freshservice Workspace Access** - confirms your API key can list the workspaces in your instance (requires the Account Administrator role or a custom role with workspace management permissions). * Success: "Successfully accessed Freshservice workspaces. Found \[number] workspace(s)." * Permissions failure: "Unable to access Freshservice workspaces. Your API token lacks the required permissions. Please reconnect using an API token from a user with the 'Account Administrator' role or a custom role with workspace management permissions." * Other errors: "Unable to connect to Freshservice API. Please verify your API token is valid and your Freshservice domain is correct." **Validate Ticket Form Fields Access** - confirms the key's user is a member of at least one workspace by reading ticket form fields for your first workspace. * Success: "Successfully validated access to Freshservice ticket form fields. During ticket sync configuration, you'll see workspaces you have access to." * Not a workspace member (403): "Unable to access Freshservice workspace form fields (403 Forbidden). This indicates the API token user is not a member of any workspaces. Please either: • Add this user to one or more workspaces in Freshservice (Admin → Workspaces), OR • Use an API token from a user with 'Account Administrator' role Note: During ticket sync configuration, the workspace dropdown will automatically show only workspaces you have access to." * No workspaces exist: "No Freshservice workspaces found. Please ensure your Freshservice instance has at least one workspace configured." * Invalid key (401): "Freshservice API authentication failed (401 Unauthorized). Your API token is invalid or expired. Please reconnect with a valid API token." * Other errors: "Unable to read ticket form fields from Freshservice. Please verify your API token is valid and has proper permissions." **List Freshservice Tickets** - confirms the key can read tickets. * Success: "Successfully retrieved tickets from Freshservice." (or, if your instance has no tickets yet: "Successfully connected to Freshservice tickets API (no tickets found).") * Failure: "Unable to read tickets from Freshservice. Please verify your API token has permissions to access tickets." All three checks can pass and ticket updates can still stop flowing - the most common cause is flipping "Enable webhook sync" before all three Freshservice Workflow Automators are configured and active. The toggle disables polling, so until your webhooks deliver, no updates arrive at all. ## Gotchas and troubleshooting The key inherits the agent's permissions. The health checks specifically require the Account Administrator role (or a custom role with workspace management permissions) to list workspaces, and membership in at least one workspace to read ticket form fields. A Requester account, an Occasional Agent, or a never-activated agent produces 401/403 errors. The UI toggle "Enable webhook sync" states: "Enable after configuring webhooks. Polling will be disabled and ticket updates will come through webhooks only." Configure and activate all three Freshservice Workflow Automators before flipping it, or ticket updates stop flowing. Without the "Ticket is Raised" automator, newly created tickets don't reach Serval until their first update. New tickets, ticket field changes, and new replies use three different webhook URLs - copy the "Ticket Create Webhook URL", "Ticket Update Webhook URL", and "New Reply Webhook URL" exactly from the ticket sync settings page, and pair them with the "Ticket is Raised", "Ticket is Updated", and "Reply is sent" Workflow Automators respectively. An unknown path is rejected with "Unknown webhook path; use /freshservice/ticket-create, /freshservice/ticket-update, or /freshservice/reply". Every request must carry the X-Serval-Webhook-Token header matching the stored webhook token (an empty stored token or missing header fails validation), the ticket source must have webhooks enabled, and the payload must include a ticket ID. Don't include "Latest Public Comment" in the ticket-create or ticket-update automators - comment data belongs only on the reply webhook. Serval resolves which connection a webhook belongs to from the payload's Helpdesk URL field (falling back to a domain segment embedded in the URL path). Include Helpdesk URL in the automator's Content selection. Display ticket IDs like INC-3982 are normalized to the numeric 3982 automatically. The form asks for Domain and API Key only. The webhook token is the read-only "Authentication Token" on the integration's ticket sync settings page - Serval generates and stores it automatically the first time that page loads - and it is only used to authenticate inbound webhooks. The field description explicitly asks for the domain without https\://. The form strips leading "http\://" or "https\://" and trailing slashes before submitting, so "[https://company.freshservice.com/](https://company.freshservice.com/)" becomes "company.freshservice.com". The update path only overwrites the API key or domain when a non-empty value is submitted. Leaving a field blank preserves what's stored - safe for rotating a single credential. The Serval-generated webhook token is never collected by the form and is always preserved. Scheduled catalog sync is intentionally paused - trigger syncs from the UI. The sync skips deleted and draft (unpublished) items, caps lookup-field dropdowns at 12 choices, retries transient gateway errors up to 2 times, and marks items with required unsupported fields (attachments, nested/dependent dropdowns, lookups whose choices couldn't be fetched) as unfillable, falling back to a link to the item's form in your Freshservice Service Portal. The Freshservice API v2 has no direct attachment upload, so Serval posts files as notes on the ticket. Attachments on catalog requests are uploaded as private, agent-only notes; the standalone attachment-upload action defaults to a public note. Older connections created under the original API-key-only storage format cannot hold a webhook token - the ticket sync settings page shows "Not configured" as the Authentication Token and webhook validation fails. Saving any update to the connection automatically migrates it to the new storage format; after that, Serval generates the token the next time the ticket sync settings page loads. Freshservice wraps responses by resource type (for example, a list of tickets arrives under a "tickets" key) and uses page-based pagination - a page number plus a per-page size of up to 100 records - so loop until an empty page. Rate limits are strict; add delays between paginated requests on large datasets. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Freshservice integration. # Front Source: https://docs.serval.com/sections/integrations/front Connect Front, the shared-inbox customer communication platform, to Serval so workflows can manage conversations, contacts, inboxes, tags, and more through the Front API. ## About Front Front is a customer communication platform built around shared inboxes for email, chat, SMS, and social channels. Serval connects to your Front workspace with a single Front API token, stored encrypted and attached automatically to every request Serval makes to the Front API. One connection covers both of Front's API surfaces: the Core API (conversations, contacts, inboxes, tags, teammates, templates, knowledge bases, analytics, and rules) and the Channel API (custom channel messaging). **Authentication:** Front API token, pasted into Serval's connect form. There is no OAuth redirect and no client secret to manage. **Data sync:** On-demand only. Serval does not run background syncs, does not ingest Front webhooks, and installs no prebuilt workflows - data is read and written at the moment a workflow runs. ## What the Front integration enables | Capability | Description | | - | - | | Manage conversations | List, search, read, and update conversations; manage assignees, followers, inboxes, links, tags, comments (including replies and mentions), drafts, messages, and reminders. | | Work with contacts and accounts | Create, read, update, and merge contacts; manage contact handles, notes, groups, and lists; manage accounts, account contacts, and custom fields. | | Administer inboxes, channels, and teammates | List and manage inboxes, channels, teammates, teammate groups, teams, shifts, signatures, and views; import messages into inboxes; create channel drafts and messages. | | Tags, rules, and statuses | Create and manage tags (including child tags and tagged conversations), company and teammate rules, and company statuses. | | Message templates | Manage message templates and template folders at company, team, and teammate level, including attachment downloads. | | Knowledge bases | Read and manage knowledge bases, categories, and articles, including per-locale content and article attachments. | | Analytics and events | Create and fetch analytics exports and reports; list and read workspace events. | | Custom channel messaging | Send inbound and outbound messages on custom channels, manage application message templates, and update message delivery status through Front's Channel API. | Anything defined in the [Front API](https://dev.frontapp.com/reference) can be accessed through Serval. ## Get your credentials Serval connects with a Front API token, which you generate from the Front dashboard. The token's scopes and permissions are set in Front when you create it, and they determine which resources Serval workflows can reach. See Front's [authentication guide](https://dev.frontapp.com/docs/authentication) for full details. Log in to your Front account at [app.frontapp.com](https://app.frontapp.com) and open **Settings**. Navigate to **Developers** and open the **API Tokens** tab. Click **Create API token** and give it a descriptive name, such as "Serval Integration". Choose what the token can reach. At minimum, enable the **Access resources** feature with the **Shared resources** scope for the workspaces Serval should access, plus the read/write/delete/send permissions your workflows will need. Copy the generated token and keep it somewhere safe until you finish connecting. If you lose the token before connecting, you do not need to start over: Front lets you reveal or copy a token's value again from its details page under **Settings** > **Developers** > **API Tokens**. Pick scopes generously enough to cover everything your workflows will do. A token with missing scopes can still connect and pass the health check, but specific workflow calls can be denied later. ## Connect in Serval In Serval, add a new Front connection. The form has a single field. Enter your token in the **API Token** field. It is marked required with a trailing asterisk and rendered as a masked password input. The helper text reads: "Your Front API token. You can generate one from Settings > Developers > API tokens in your Front dashboard." Submit the form. Serval stores the token encrypted and uses it to authenticate every Front request your workflows make. Serval does not test the token against Front when you connect, and the form does not block an accidental blank submission - whatever you submit is stored as-is. Double-check that you pasted the full token, then run the health check (below) right after connecting to confirm it actually works. When editing an existing Front connection, always paste the complete API token before saving - do not save while the field is blank and do not save with the pre-filled masked value still in place. After any edit, re-run the health check to confirm the connection still works. ## Verifying the connection The Front integration ships one health check. **Validate Front API Connection** - asks Front to identify who the token is authenticated as. On success it reports: "Successfully connected to Front API. Authenticated as \[first name] \[last name] (\[email])." On failure it reports: "Unable to connect to Front API. Please verify your API token is valid and has the necessary permissions." A green health check confirms the token authenticates, not that it can reach everything. Front tokens carry their own scopes, so a workflow can still be denied on specific resources even when the check passes. If a workflow call is denied, create a new token in Front with the missing scopes and update the connection. ## Gotchas and troubleshooting When you open the connection settings, treat the credential as something you must re-supply. Always paste the complete API token before saving any change to the Front connection - never save while the field is empty or still showing the masked placeholder, or the integration can silently stop working. Run the health check after every edit. Serval performs no test call against Front at connect time, so an invalid or revoked token is accepted and saved without complaint. The problem only surfaces when the Validate Front API Connection health check or a workflow call fails. Run the health check immediately after connecting. The health check only verifies that the token authenticates. A token can pass yet be denied on specific resources your workflows use because its scopes were set too narrowly in Front. If that happens, create a new token in Front with the missing scopes and update the connection, re-entering the full token. When you revisit the connection, Serval shows the token as bullets plus its last 4 characters, with a control to replace it. This is a display-only mask - Serval never reveals the full token again. To rotate the token, use the replace control, paste the complete new token, and save; if you need to see a token's value, reveal it from the token's details page in Front instead. Serval authenticates requests only to Front's official API host (api2.frontapp.com). There is no per-region or custom-domain configuration - all workflow calls, for both the Core API and the Channel API, go to that one service. Front returns list data in pages with a next-page cursor rather than page numbers. A single workflow call retrieves one page of records, and the workflow must follow the next-page cursor until it is absent to gather the full set. If a workflow seems to be missing records, check that it pages through all results. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Front integration. # Google Cloud Platform Source: https://docs.serval.com/sections/integrations/gcp Connect Google Cloud Platform to Serval so workflows can manage projects, IAM role grants, and any other GCP resource on demand. ## About Google Cloud Platform Google Cloud Platform (GCP) is Google's cloud — projects, IAM, Compute Engine, Cloud Storage, and every other Google Cloud service. The Serval integration lets workflows reach any GCP API through Serval's authenticated proxy, and it ships two ready-to-install workflows for granting and revoking project IAM roles. Three built-in health checks confirm that authentication works, that the connection can see your projects, and that it can read IAM policy. **Authentication:** A Google Cloud service account key (JSON) that you create and control. Serval acts as that service account; what workflows can do is bounded by the IAM roles you grant it. **Data sync:** On-demand only. Nothing is synced into Serval on a schedule — workflows call Google Cloud at run time, and Serval mints short-lived access tokens automatically for each request. ## What the GCP integration enables | Capability | Description | | - | - | | GCP API requests from workflows | Workflows can make any read or write call to Google Cloud APIs — Cloud Resource Manager, IAM, Compute Engine, Cloud Storage, and any other service on a googleapis.com endpoint. | | Grant GCP Project IAM Role (installable workflow) | Grants an IAM role (predefined like `roles/viewer`, or custom) to a user, group, or service account on a project. If the principal already holds the role, the workflow reports success with no action taken. Requires installer approval by default. | | Revoke GCP Project IAM Role (installable workflow) | Removes an IAM role from a user, group, or service account on a project. If the principal does not hold the role, the workflow reports success with no action taken. Requires installer approval by default. | | Health checks | Three built-in checks — "Test GCP Connection", "List Accessible GCP Projects", and "Read Project IAM Policy" — verify that the integration can authenticate, see your projects, and read IAM policy. | Anything defined in the [Google Cloud API reference](https://cloud.google.com/apis/docs/overview) can be accessed through Serval. ## Get your credentials You will create a dedicated service account, grant it the IAM roles your workflows need, and download a JSON key for it. Google's official guide is [Create service accounts](https://cloud.google.com/iam/docs/service-accounts-create). Sign in to the [Google Cloud Console](https://console.cloud.google.com), select the project that should own the service account, and go to **IAM & Admin → Service Accounts**. Click **Create service account**. Name it (for example, "serval-integration"), optionally add a description, and click **Create and continue**. Grant the roles your workflows need. For the built-in health checks and IAM workflows on this project, **Viewer** (`roles/viewer`) plus **Project IAM Admin** (`roles/resourcemanager.projectIamAdmin`) is a good starting point. To manage other projects, grant the service account roles on those projects too (their **IAM** page → **Grant access**, using the service account's email). The connection can only do what these roles allow. Granting broad roles like Owner gives Serval workflows the same reach — prefer the narrowest roles that cover your use cases. Open the new service account, go to **Keys → Add key → Create new key**, choose **JSON**, and click **Create**. The key file downloads once — store it securely and delete local copies after connecting. At minimum, enable the **Cloud Resource Manager API** in the service account's project (used by the health checks and IAM workflows). Enable any other APIs your workflows will call (Compute Engine, Cloud Storage, ...) in the projects that own those resources. ## Connect in Serval Open the Google Cloud Platform integration in Serval and click **Connect**. Optionally name the connection (it defaults to the service account's project ID), paste the full contents of the downloaded JSON key file, and submit. Serval validates the key against Google before saving — a disabled, deleted, or malformed key is rejected immediately with Google's reason. Run the built-in health checks to confirm the connection can see your projects and read IAM policy. For Google Workspace administration (users, groups, Drive, Gmail, Calendar), use the [Google Workspace](/sections/integrations/google-workspace) integration instead — those APIs require domain-wide delegation, which this integration does not use. ## Rotating the key Create a new JSON key for the same service account in Google Cloud IAM, then edit the connection in Serval and paste the new key. The connection's identity is the service account's email, so a replacement key must belong to the same service account — connecting a different service account is a new connection. After Serval accepts the new key, delete the old key in Google Cloud IAM. # GitBook Source: https://docs.serval.com/sections/integrations/gitbook Connect GitBook to Serval so workflows can search a GitBook space and read matching pages as Markdown. ## About GitBook GitBook is a documentation and knowledge base platform. The Serval GitBook integration connects to GitBook with a personal access token, giving Serval workflows read-only access to GitBook content through Serval's authenticated proxy. The integration includes a ready-to-use workflow, **Search and Read GitBook Pages**, that searches a space and reads matching pages as Markdown. **Authentication:** API token. GitBook calls these personal access tokens. Serval stores the token securely and attaches it to requests automatically; the token is only sent to GitBook's API host (`api.gitbook.com`), and workflow code never sees it. **Data sync:** On demand only. Workflows read from GitBook at run time. There is no background sync or webhook setup in this integration. ## What the GitBook integration enables | Capability | Description | | - | - | | GitBook API requests from workflows | Workflows can call the modeled GitBook API surface through Serval's built-in GitBook action, with your token injected automatically. | | Search and read pages | The **Search and Read GitBook Pages** workflow searches one GitBook space, reads up to 10 matching pages, and returns each page's title, path, URL when available, excerpt, and Markdown content. | | Health checks | Two checks verify that the token can read the current user and list spaces visible to that user. | Anything in the integration's modeled GitBook API surface can be accessed through Serval, including current-user lookup, space listing, space search, current revision lookup, and page retrieval by ID or path. ## Get your credentials You need a GitBook personal access token. GitBook tokens are tied to the user account that creates them and have the same access that user has in GitBook. In GitBook, open your user account's Developer settings. GitBook documents token management under [API authentication](https://gitbook.com/docs/developers/gitbook-api/authentication). Create a new access token for Serval. Copy it immediately and store it securely. Make sure the GitBook user that created the token can read every space and page Serval workflows should access. A token cannot read content that its user cannot see. Treat the token like a password. If it is shared or exposed, revoke it in GitBook Developer settings and create a replacement token. ## Connect in Serval In Serval, open the **GitBook** integration and start a new connection. Paste the personal access token into the **API Token** field. The field is a password field, so the value is hidden as you type. Submit the form, then run the health checks below to confirm the token works and has access to the expected spaces. ## Find your GitBook space ID The **Search and Read GitBook Pages** workflow requires a `spaceId`. You can find a space ID in either place: * In a GitBook space URL: `https://app.gitbook.com/o//s/`. The value after `/s/` is the space ID. * In GitBook's space menu, use **Copy space ID** when it is available. ## Verifying the connection After connecting, run the integration's health checks from the integration page: * **Get GitBook Current User** - verifies that the token authenticates by reading the current GitBook user. * Success: "Successfully connected to GitBook as \[display name]." If GitBook returns an email address, the message includes it in parentheses. * Failure: "Unable to read the current GitBook user. Please verify your API token is valid." * **List GitBook Spaces** - verifies that the token can list spaces visible to the current user. * Success: "Successfully listed \[number] GitBook space(s)." * Failure: "Unable to list GitBook spaces. Please verify your API token has read access." A successful connection only proves that the token works. The spaces and pages available to workflows still depend on what the token's GitBook user can read. ## Gotchas and troubleshooting Confirm the `spaceId` belongs to the space you want to search and that the token's GitBook user can read that space. Also try a shorter search query. GitBook's space search can be strict about matching all words in a query. The token reads as the GitBook user who created it. If that user cannot open the page in GitBook, Serval cannot read it either. Grant the user access or create the token from a user with the right access. Use the internal GitBook space ID, not the published docs URL. In `https://app.gitbook.com/o//s/`, copy only the value after `/s/`. When rotating the token, paste the complete replacement token into Serval and save. Do not save a blank or partial value; Serval will use exactly what you submit. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your GitBook integration. # GitHub Source: https://docs.serval.com/sections/integrations/github Connect GitHub to Serval to run repository, team, and enterprise workflows and manage GitHub Team access - authenticated entirely through GitHub Apps. ## About GitHub Serval's GitHub integration connects your GitHub Organization, User account, or Enterprise to Serval so workflows can read repositories, manage teams, and call the GitHub API on your behalf. It authenticates exclusively through GitHub Apps - never personal access tokens. You choose between two Serval-managed apps with different access tiers, or bring a GitHub App owned by your own organization. **Authentication:** GitHub App installation only. Pick a Serval-managed app - **Full Admin Access** or **Code Contributor Access** - or choose **Use Your Own GitHub App**. The bring-your-own path offers two options: let Serval walk you through installing the app (**Install with Serval**), or connect an app your GitHub organization admin already installed out of band (**App already installed**) by pasting its credentials. Workflow API calls never rely on a stored long-lived token: a fresh, short-lived installation access token is minted for every call. **Data sync:** Workflow API calls run on demand. For Access Management, GitHub Teams are ingested on a fixed schedule every 16 hours, always as a full sync (GitHub does not support delta sync). ## What the GitHub integration enables | Capability | Description | | - | - | | Get GitHub Repository Info | Retrieve detailed information about a GitHub repository. Runs without approval by default. | | Get GitHub File Contents | Retrieve the contents of a file from a GitHub repository. Runs without approval by default. | | List GitHub Repository Contents | List files and directories in a GitHub repository path. Runs without approval by default. | | List GitHub Repositories | List all repositories in a GitHub organization. Runs without approval by default. | | List GitHub Teams | List all teams in a GitHub organization - the only approved way to fetch teams. Runs without approval by default. | | Add GitHub User to Team | Add a user to a GitHub team, with validation that the team exists. Requires the user's GitHub username, not an email address. Requires installer approval by default. | | List GitHub Enterprise Roles | List custom enterprise roles defined on your GitHub enterprise. Requires an enterprise-scoped install. Runs without approval by default. | | Update GitHub Enterprise Administrator Role | Set an enterprise member's administrator role to Owner or Billing Manager. Requires an enterprise-scoped install. Requires installer approval by default. | | Generic REST API requests | Typed access to any endpoint in GitHub's official REST API from custom workflows, limited by the installed app's permissions. | | Enterprise REST API requests | A dedicated action for enterprise-only GitHub endpoints, intended for enterprise-scoped installs. | | GraphQL requests | Run queries and mutations against GitHub's GraphQL API; GraphQL-layer errors are surfaced as failures rather than silently dropped. | | Access Management for GitHub Teams | GitHub Teams are ingested as resources (full sync every 16 hours) with **Member** and **Maintainer** entitlements. Users can request team access through Serval, and membership is provisioned and deprovisioned automatically. | Anything defined in the [GitHub API](https://docs.github.com/en/rest) can be accessed through Serval. ## Get your credentials What you need depends on which connect option you choose in the **Connect GitHub** modal. Nothing to create. Both **Full Admin Access** ("Read contents of selected repos, open pull requests, create and manage repos and teams, invite users") and **Code Contributor Access** ("Read contents of selected repos, open pull requests, and comment on issues") use GitHub Apps that Serval manages - no credentials are required. The install must be performed by (or approved by) a **GitHub Organization Owner**. If you're not an owner, your install lands in a pending state until an owner approves it in GitHub - see Gotchas below. You'll need a GitHub App owned by your organization, plus a client secret and a private key generated for it. Follow GitHub's app settings pages in [GitHub Developer Settings](https://github.com/settings/apps). Use Serval's **Create your GitHub App on GitHub** button, which opens the registration page with the OAuth-on-install setting already ticked. Enter your organization name in the connect form first if the app should be owned by your org - GitHub fixes the owner by which URL you open (`https://github.com/organizations//settings/apps/new` for an org, `https://github.com/settings/apps/new` for your personal account), and the registration form has no owner picker. Under **Identifying and authorizing users**, paste the **Redirect URI** Serval shows below the button, and confirm **"Request user authorization (OAuth) during installation"** is checked. Confirm **Allow wildcard matching** is off - Serval uses one exact redirect URI, and wildcards widen it to every subdomain and path beneath it. Then fill in the **Homepage URL** GitHub requires and choose the app's permissions. **Webhook → Active** is checked by default and GitHub then requires a Webhook URL, so untick it if you have no webhook endpoint. GitHub labels this field **Redirect URI**, under "Identifying and authorizing users" - not "Callback URL". Serval completes the install handshake through it and the OAuth-on-install setting, so don't clear either one. GitHub creates the app and takes you to its settings page. The remaining values only exist from this point on - there are no **Client secrets** or **Private keys** sections on the registration form. Under **Client secrets**, click **Generate a new client secret** and copy it. GitHub only shows the client secret once. Copy it before leaving the page. Under **Private keys**, click **Generate a private key** and save the downloaded `.pem` file. You'll paste its full contents into Serval, including the BEGIN/END lines. From the app's **About** section, note the numeric **App ID**, the **Client ID** (starts with "Iv"), and the **Public link** (your app's public page on GitHub). These plus the client secret and `.pem` contents fill Serval's form. Use the key GitHub generates for you, unmodified. Serval's validation only accepts the RSA private key format GitHub's **Generate a private key** button produces (the file begins with `-----BEGIN RSA PRIVATE KEY-----`) - keys converted to other formats will be rejected. Use this option when your security process requires the app to be installed **separately by an authorized organization admin** after the app and its permissions have been reviewed - not inline during Serval's connect flow. Your admin creates the app, configures permissions, transfers it to the organization, and installs it entirely on GitHub; Serval never triggers the install and no OAuth callback is involved. Because Serval authenticates purely as the app (a signed JWT minted from the private key), this path needs **no OAuth client secret and no "Request user authorization (OAuth) during installation"** setting. You only collect three values, all readable by an org owner from the app's settings and installed-apps pages: An organization owner installs the GitHub App on the org with the approved repository access, following your normal review/approval process. In the app's **Settings → Private keys**, click **Generate a private key** and save the downloaded `.pem` file. Only an admin of the app can generate it, and GitHub shows it only at generation time. The numeric **App ID** is in the app's **About** section. For the **Installation ID**, open the org's **Installed GitHub Apps** settings and click **Configure** on the app - the number at the end of the URL (`.../installations/`) is the installation ID. The **private key is the sensitive credential** on this path - it can mint installation tokens for the app, so treat it as a secret and prefer a dedicated key you can rotate or revoke independently. Possession of the key is also what authorizes the connection (there is no OAuth ownership check), which cleanly separates the admin's install action on GitHub from the connect action in Serval. ## Connect in Serval Click **Connect** on GitHub in Serval. The modal asks you to "Choose the access level that best suits your needs" - pick **Full Admin Access** or **Code Contributor Access**. Serval opens GitHub's install screen. Pick the target organization (or user or enterprise account), then choose **all repositories** or **only selected repositories**, and click **Install & Authorize**. GitHub sends you back to Serval, which records the installation and names the connection after your org or user login (or the enterprise slug for Enterprise installs). No credentials are ever entered. Repository selection and access tier are fixed at install time. Repositories can be adjusted later in GitHub's installed-apps settings; switching tiers requires uninstalling in GitHub and reconnecting with the other tier. Choosing **Use Your Own GitHub App** ("Connect with a GitHub App owned by your organization.") switches the modal to a bring-your-own form with a toggle at the top: **Install with Serval** (the guided two-step form below) and **App already installed** (paste credentials for an app your admin installed out of band - see the next tab). **Install with Serval** is the default. Optionally enter the **GitHub organization** that should own the app, then click **Create your GitHub App on GitHub**. The button opens GitHub's Create GitHub App page with **"Request user authorization (OAuth) during installation"** already ticked. Copy the read-only **Redirect URI** below it (the Copy button shows "Copied" for 2 seconds) into GitHub's **Redirect URI** field - GitHub does not accept a redirect URI supplied through the link. * **Display name** (optional) - "A friendly name shown in Serval - you choose this." Placeholder: "My Company GitHub App". * **GitHub App public link** (required) - accepts the full Public link, a scheme-less form, or a bare slug; the form shows `Detected slug: [slug]` once parsed. If it can't be parsed: `Couldn't read the GitHub App slug from that link. Paste your app's Public link, e.g. https://github.com/apps/your-app-name.` Backend errors: `appSlug is required`, `appSlug must be a valid GitHub App slug`. * **App ID** (required) - must be numeric. Errors: `appId is required`, `appId must be numeric`. * **Client ID** (required) - starts with "Iv". Error: `clientId is required`. * **Client secret** (required, password field) - "The value you copied in step 4 (GitHub won't show it again)." Error: `clientSecret is required`. * **Private key PEM** (required, multi-line) - paste the full `.pem` contents including the BEGIN/END lines. Serval validates the key by signing a test token. Errors: `privateKey is required`, `privateKey must be a valid GitHub App private key: [error details]`. Click **Connect**. Serval validates your entries, then sends you to GitHub to install your app - pick the account and repositories and click **Install & Authorize**. Serval then verifies that the installed app matches the App ID you entered; if they don't match, the connection fails with `Failed to create integration` - double-check that the Public link and App ID belong to the same GitHub App. Complete the GitHub install promptly - your submitted credentials are held for only **10 minutes**. If the window lapses you'll see `Invalid or expired OAuth state` and must resubmit the form. **Reconnecting:** the form prefills Display name, GitHub App public link, App ID, and Client ID from the saved connection, but **Client secret and Private key PEM always start blank and are required again** - there is no keep-existing-secret option. Have the `.pem` file and a client secret on hand (or generate new ones in GitHub) before reconnecting. In the **Connect GitHub** modal, choose **Use Your Own GitHub App**, then switch the toggle to **App already installed**. There is no redirect URI to copy and no redirect to GitHub - the app is already installed, so you just enter its credentials and connect. * **Display name** (optional) - a friendly label shown in Serval; you choose it. * **App ID** (required) - must be numeric. Errors: `appId is required`, `appId must be numeric`. * **Installation ID** (required) - must be numeric. Errors: `installationId is required`, `installationId must be numeric`. * **GitHub App public link** (optional) - stored for reference; when provided it must parse to a valid slug (`appSlug must be a valid GitHub App slug`). * **Private key PEM** (required, multi-line) - paste the full `.pem` contents including the BEGIN/END lines. Errors: `privateKey is required`, `privateKey must be a valid GitHub App private key: [error details]`. Click **Connect**. Serval authenticates as the app to confirm the installation is real and belongs to the App ID you entered, records the connection, and names it after your organization or user login. If verification fails you'll see `Could not verify the GitHub App installation. Double-check the App ID, Installation ID, and private key, and confirm the app is installed on your organization.` **Reconnecting:** Display name, GitHub App public link, App ID, and Installation ID are prefilled from the saved connection, but the **Private key PEM starts blank and is required again**. The modal reopens on this option automatically when the saved connection was created this way. This path is for **organization or user** installs. An enterprise-scoped app is rejected with `this app is installed on a GitHub Enterprise. Use the GitHub Enterprise integration to connect an enterprise-scoped app` - use **GitHub Enterprise → App already installed** instead. Enter the enterprise app’s **App ID**, **Installation ID**, and **Private key PEM**. Find the Installation ID in the installed app’s configuration URL in your enterprise settings: the number after `/installations/`. This connects the existing enterprise installation without reinstalling or configuring OAuth. ## Connecting GitHub Enterprise In **GitHub Enterprise**, choose **Install with Serval** for a new installation or **App already installed** to connect an existing enterprise installation with its App ID, Installation ID, and private key. **Reconnecting:** Serval restores the original connect mode and saved app details, including the App ID and Installation ID. Private keys and client secrets must be entered again. For a new app, enter your enterprise account name before opening the creation link. Serval opens that enterprise’s registration page with **Request user authorization (OAuth) during installation** selected. Paste the **Redirect URI** shown in the Enterprise connect form into GitHub, leaving **Allow wildcard matching** off. Return to Serval and complete **Connect**; saving the app’s settings alone does not connect it. ## Verifying the connection Serval runs three health checks against a connected GitHub integration: 1. **Test GitHub App Installation** - verifies a token can be minted and works, by making a small test request (a sample of accessible repositories for org/user installs, or a single enterprise team for Enterprise installs). * Success: `GitHub App installation for [name] is properly configured and functional` - or, for enterprise installs, `GitHub Enterprise App installation for [name] is properly configured and functional` * Failure: `GitHub App installation token for [name] is invalid or not working.` followed by a status-specific hint: * 401 - `The GitHub App installation token is invalid or expired. Please reinstall the GitHub App.` * 403 - `The GitHub App may not have the required permissions. Check the app's permission configuration.` * 404 - `The GitHub App installation was not found. It may have been uninstalled or it may be awaiting approval from an admin of [name]. Visit https://github.com/organizations/[name]/settings/installations for more info.` * 500/502/503 - `GitHub returned a server error. This is likely a temporary issue with GitHub's API - please try again later.` 2. **List GitHub Teams** - confirms the integration can list teams in the connected scope (org teams, or enterprise teams for Enterprise installs). * Success: `Successfully listed [number] teams in [name]` - or, for enterprise installs, `Successfully listed [number] enterprise teams in [name]` * Failure: `Unable to list GitHub teams in [name].` followed by the same 401/403/server-error hints; the generic 404 variant reads `The requested resource was not found. This may indicate missing permissions or incorrect configuration.` 3. **List GitHub Repositories** - confirms the integration can list accessible repositories for the org. Enterprise installs skip this check and report it as passing. * Success: `Successfully listed [number] repositories for [name]` - enterprise installs instead report `Not applicable: this check only validates org/user installs. Enterprise install ([name]) covered by test-installation-token.` * Failure: `Unable to list GitHub repositories for [name].` followed by the same 401/403/404 (generic)/server-error hints. If all three checks are green but a specific workflow still fails with a permission error, the cause is almost always install-time scoping: the access tier you chose (Full Admin vs Code Contributor), the repository selection (all vs selected), or - on Enterprise installs - workflows that require an organization install. Check the app's settings in GitHub's installed-apps page, and see the gotchas below. ## Gotchas and troubleshooting If the person connecting isn't a GitHub Organization Owner, GitHub treats the install as a request and Serval creates a pending connection. Until an owner approves the app in GitHub, every API call fails with `GitHub installation is pending approval`. Once approved, the connection completes automatically - Serval matches the pending record even if the approval finishes outside the original browser session, returning the approver to Serval (or showing `GitHub installation completed. You can close this window.` when no return destination was recorded). If more than one pending install exists for the same GitHub target, completion errors with `multiple pending installations found for this GitHub target - please keep only one`. If your security process requires an authorized org admin to install the reviewed app **separately** rather than inline during a vendor's connect flow, use **Use Your Own GitHub App → App already installed**. Serval authenticates as the app via a signed JWT, so this path needs no OAuth callback and no client secret - only the App ID, Installation ID, and private key. There is no 10-minute credential window and no pending-approval handshake: the admin installs the app on GitHub first, then anyone with the credentials connects it in Serval. Because there is no OAuth ownership check on this path, **possession of the private key is the authorization** - treat it as a secret and use a dedicated, rotatable key. For **Use Your Own GitHub App**, submitted credentials are held for only 10 minutes. If your org requires admin approval, the connection rejects with `GitHub App installation is pending approval. Ask a GitHub organization owner to approve the app, then reconnect it in Serval.` - your credentials are deliberately kept so an immediate retry works, but only until the 10 minutes expire, after which you'll see `Invalid or expired OAuth state` and must resubmit the form. On reconnect, Display name, GitHub App public link, App ID, and Client ID are prefilled, but **Client secret** and **Private key PEM** always start blank and are hard-required - submit is blocked and blanks are rejected with `clientSecret is required` / `privateKey is required`. There is no keep-existing-secret path. Have the `.pem` file and a client secret ready (or generate fresh ones in GitHub) before you start. An Enterprise-scoped install is tied to the enterprise, not an organization. Workflows that inherently target an organization fail with `This workflow requires a GitHub organization install, but the connected install is enterprise-scoped ([name]).` Team ingestion returns an empty set for enterprise installs, the repository health check is reported as not applicable, and enterprise-only endpoints require the dedicated enterprise API action. Team ingestion never creates new Serval users, because GitHub emails may be missing or personal. The **Add GitHub User to Team** workflow rejects anything that looks like an email address with `Invalid GitHub username: '[username]'. Please provide a GitHub username (not an email address). GitHub usernames typically contain only letters, numbers, and hyphens.` Access Management provisioning is likewise instructed never to guess: its input is annotated "The target user's GitHub username. Do not make guesses about the user's username. Ask the user for their GitHub username." Tokens are minted fresh for every API call, so an uninstall (or an unapproved install) surfaces right away as `The GitHub App installation was not found. It may have been uninstalled or it may be awaiting approval from an admin of [name]. Visit https://github.com/organizations/[name]/settings/installations for more info.` Which repositories Serval can read is decided on GitHub's install screen (all vs selected) and managed afterward in GitHub's installed-apps settings, not in Serval. The two Serval-managed tiers are separate GitHub Apps - switching tiers means uninstalling the current app in GitHub and reconnecting with the other one. GitHub does not support incremental sync, so every scheduled run re-enumerates all teams, their repositories, and memberships. Newly created GitHub teams appear after the next scheduled sync or a manual resync. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your GitHub integration. # GitLab Source: https://docs.serval.com/sections/integrations/gitlab Connect GitLab to Serval with a personal access token so workflows can call the full GitLab REST API on gitlab.com or your self-managed instance. ## About GitLab GitLab is a DevOps platform for source control, issues, merge requests, and CI/CD. Serval connects to gitlab.com or any self-managed GitLab instance using a GitLab personal access token: you paste it in once, Serval stores it encrypted and attaches it to every request a workflow makes, using GitLab's standard private token header. The instance domain you enter at connect time becomes the base for every request, so one integration covers both GitLab SaaS and self-hosted deployments. **Authentication:** GitLab personal access token, plus the instance domain. There is no OAuth or sign-in flow. **Data sync:** No background sync and no webhooks. Serval contacts GitLab only on demand - when a workflow runs, and when health checks run after connecting or from the integration settings page. ## What the GitLab integration enables | Capability | Description | | - | - | | Full GitLab REST API access | Workflows use a single generic GitLab API request action to call any part of the GitLab REST API v4 - roughly 1,300+ typed paths covering the full API surface, generated from GitLab's OpenAPI spec. | | Work with projects and groups | List and read projects and groups. Identifiers can be numeric IDs or URL-encoded full paths (for example my-group%2Fmy-project). | | Automate issues and merge requests | Read and write issues, merge requests, pipelines, and related resources through the same API request action (writes require the api token scope). | | SaaS or self-managed instances | Point the connection at gitlab.com or any self-hosted GitLab domain - the same integration works against either deployment model. | Anything defined in the [GitLab REST API](https://docs.gitlab.com/api/rest/) can be accessed through Serval. ## Get your credentials Serval needs a **GitLab personal access token**. Choose the scope based on what your workflows will do: **read\_api** for read-only workflows, or **api** if workflows will create or update GitLab resources. GitLab's official guide is here: [GitLab personal access tokens documentation](https://docs.gitlab.com/user/profile/personal_access_tokens/). In GitLab, open your avatar menu and select **Edit profile**. On gitlab.com you can go directly to the [personal access token settings page](https://gitlab.com/-/user_settings/personal_access_tokens) (sign-in required); on a self-managed instance, the same settings page lives under your own domain. In the left sidebar, select **Access Tokens**. Click **Add new token**. Enter a descriptive token name (for example "Serval Integration") and an expiration date per your security policy. Choose **read\_api** for read-only workflows, or **api** for read/write. Click **Create personal access token** and copy the value immediately - GitLab shows it only once. Create the token on the same GitLab instance you plan to connect. A token issued on gitlab.com will not work against a self-managed instance, and vice versa. If you set an expiration date, note it down. An expired token fails silently until a health check or workflow run surfaces the error - plan to rotate before it lapses. ## Connect in Serval Add a new GitLab connection from your Serval integrations page. The **Instance Domain** field is a text field with the placeholder "gitlab.com". Leave it blank if you use GitLab SaaS - it defaults to gitlab.com. If you run a self-managed instance, enter its domain. The field is not marked required and applies no format validation. The **Personal Access Token** field is a password field. The form does not mark it required and will accept an empty submission, but the connection cannot work without it - every API call fails until a valid token is saved. Submit the connection. If something goes wrong, the connect form on an application page shows the toast "Failed to connect service"; the underlying error reads "Failed to install integration", with details appended when GitLab or Serval returns any. Serval does not test or format-check either field when you save - a blank token or a mistyped domain is accepted at save time and only surfaces when the health checks run. Run them right after connecting (see below). After saving, the token is displayed masked - bullet characters plus its last 4 characters - with a pencil icon next to it. Clicking the pencil opens an empty "Enter new value" box for the replacement token. When you later edit the connection, leaving the token field untouched or blank keeps your existing stored token, and leaving the Instance Domain blank keeps the existing domain. To rotate the token, paste the complete new value into the field, save, and re-run the health checks. ## Verifying the connection The connection ships two health checks that make live calls to your GitLab instance. They run automatically after connecting (if enabled) and on demand from the integration settings page: * **Validate GitLab API Connection** - makes a lightweight call to your instance to confirm the personal access token authenticates against the configured domain. Success: "Successfully connected to GitLab API. Instance version: \[version]." Failure: "Unable to connect to GitLab API. Please verify your personal access token is valid and your instance domain is correct." * **List GitLab Projects** - lists a small sample of projects (up to 5) to confirm the token actually has API read access. Success: "Successfully listed GitLab projects. Found \[number] project(s)." A count of 0 still passes - it means the token works but its user has no visible projects. Failure: "Unable to list GitLab projects. Please verify your token has the appropriate scopes (read\_api or api)." If **Validate GitLab API Connection** passes but **List GitLab Projects** fails, the token is reaching the right instance but lacks API read access. Recreate the token with the **read\_api** or **api** scope and update the connection. ## Gotchas and troubleshooting The Instance Domain is the base for every request, and tokens are instance-specific: a token issued on gitlab.com will not authenticate against a self-managed domain, and vice versa. If **Validate GitLab API Connection** fails, confirm both that the token is valid (not expired or revoked) and that the Instance Domain matches the instance where the token was created. Neither form field is marked required and there is no format validation, so a blank token or a malformed domain is accepted and the connection is created anyway. Problems only surface when the health checks run - treat green health checks, not a successful form submit, as confirmation the connection works. The **read\_api** scope is sufficient for listing and reading projects, groups, issues, and merge requests. The **api** scope is required for workflows that create or update GitLab resources. The **List GitLab Projects** health check fails with a scope hint ("Please verify your token has the appropriate scopes (read\_api or api).") when the token authenticates but lacks API read access. A note for whoever builds workflows on this connection: Serval does not add GitLab's version prefix to request paths, so every path must start with /api/v4/ as written. Project and group identifiers can be numeric IDs or URL-encoded full paths such as my-group%2Fmy-project. List results come back as plain arrays, and pagination is page-based - pass the page and per\_page query parameters and loop until an empty page. Edit the GitLab connection, click the pencil icon next to the masked token, and paste the complete new token into the "Enter new value" box, then save. Saving with the token field blank keeps the previously stored token, so a rotation only takes effect when you actually enter the new value. If the update fails, the settings page shows "Failed to update configuration". Re-run the health checks afterward to confirm the new token works. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your GitLab integration. # Gong Source: https://docs.serval.com/sections/integrations/gong Connect Serval to Gong with an API key pair so workflows can search recorded sales calls and answer questions grounded in Gong's AI-generated call summaries. ## About Gong Gong is a revenue intelligence platform that records and analyzes sales and customer calls. Serval connects to your Gong instance with a company-level API key pair (an Access Key and a Secret Key) plus your account-specific API Base URL. Once connected, Serval workflows can search your recorded calls and read Gong's AI-generated briefs, outlines, and highlights - for example, to answer a question about a customer's recent calls. **Authentication:** API key (Access Key + Secret Key pair, generated by a Gong Technical Administrator). This is a static credential - there is no OAuth consent screen and no token refresh. **Data sync:** On-demand only. Serval does not run background syncs or import Gong data ahead of time; it reads from Gong at the moment a workflow runs or the connection health check fires. ## What the Gong integration enables | Capability | Description | | - | - | | Search calls | Find recorded calls within a date range. | | Read AI-generated call content | Pull Gong's briefs, outlines, highlights, points of interest, speakers, and participants for specific calls. | | Answer Question About Customer Call (pre-built workflow) | Give it a customer name and a question; it finds that customer's calls from the last 90 days, reads Gong's AI summaries for the most recent matches (5 by default), and answers the question, citing which calls the answer came from. | | Full API access | Workflows can make any authenticated request to the Gong API - call recordings and transcripts, users and interaction stats, the call library, and more - with no extra setup per endpoint. | Anything defined in the [Gong API](https://app.gong.io/settings/api/documentation) can be accessed through Serval. ## Get your credentials You need three values from Gong: your API Base URL, an Access Key, and a Secret Key (Gong calls it the "Access Key Secret"). All three appear together on Gong's API settings page. Gong documents the process in [Receive access to the API](https://help.gong.io/docs/receive-access-to-the-api). API access must be included in your Gong plan, and only Technical Administrators can generate API keys. Click settings in the bottom left of Gong. Admins can also reach this page directly via [Gong API key management](https://app.gong.io/company/api) (sign-in required). If you don't see the API option, your Gong plan may not include API access, or you may need Technical Administrator permissions. Gong generates two values: an Access Key (the public half) and an Access Key Secret (the private half). You will paste both into Serval in the next section. It is shown on the same API settings page and follows the pattern [https://XX-00000.api.gong.io/](https://XX-00000.api.gong.io/), where XX-00000 identifies your Gong instance. The Access Key Secret is shown only once, when it is generated. If you lose it, you must generate a new key pair in Gong and update your Serval connection with both new values. ## Connect in Serval Start a new Gong connection from Serval's integrations page. Required. Paste the URL exactly as Gong displays it, for example [https://XX-00000.api.gong.io/](https://XX-00000.api.gong.io/). The placeholder reads "API Base URL (e.g. [https://XX-00000.api.gong.io/](https://XX-00000.api.gong.io/))" and the helper text reads "Your Gong API base URL, found in your Gong account settings". Serval strips the protocol prefix and any trailing slash automatically when saving. A password-style field with the helper text "Your Gong API access key". A password-style field with the helper text "Your Gong API secret key". All three fields are required, but only the API Base URL is checked in the form - leaving it blank shows "This field is required" and blocks submission. A blank Access Key or Secret Key is caught on the server instead, and the save fails with a generic "Failed to install integration" error. Submitting saves the credentials immediately - Serval does not make a test request to Gong at this point, so use the health check below to confirm the keys work. Serval automatically combines your Access Key and Secret Key into a Base64-encoded Basic Authentication header on every request. Just enter the raw credentials as provided by Gong. When you later edit the connection, the Access Key and Secret Key appear masked (bullet characters plus the last 4 characters), and the API Base URL shows the saved value without the protocol prefix. Untouched fields (and a blanked-out API Base URL) keep their stored values, so you can change one field without re-entering the others. To replace a key, use the edit control next to its masked value (a Replace button or pencil icon, depending on where you edit) and enter the new value. ## Verifying the connection Serval runs a single connection health check for Gong: it asks Gong to list the users in your account using the stored credentials and API Base URL. A passing check confirms the Access Key, Secret Key, and API Base URL are all valid and that the key can read user data. There are no Gong-specific failure messages - if the check fails, Serval surfaces the underlying error from the request. An authentication error usually means a mistyped key or a wrong API Base URL; re-enter the values from your Gong API settings page. Because connecting does not test credentials, the health check (or the first workflow run) is where a bad key first shows up. Health check green, but the "Answer Question About Customer Call" workflow reports no calls found? That is usually not a credential problem: the workflow only searches the last 90 days and matches the customer name against call titles and participant names as recorded in Gong. Try the name exactly as it appears in Gong. ## Gotchas and troubleshooting Submitting the connect form saves the keys without contacting Gong. Mistyped keys or a wrong API Base URL only surface when the health check or the first workflow run reaches the Gong API. After connecting, check the connection's health status before relying on it. Serval only sends Gong requests to hosts ending in .gong.io. If the API Base URL points anywhere else, Serval refuses to proxy the request at all - it fails before leaving Serval, with an error saying the request URL is not allowed. Always use the account-specific URL from your Gong API settings page (pattern [https://XX-00000.api.gong.io/](https://XX-00000.api.gong.io/)); the protocol and trailing slash are removed automatically. "Answer Question About Customer Call" looks at calls from the last 90 days and matches the customer name case-insensitively against call titles and participant names and affiliations. Older calls, or a customer recorded under a different name in Gong, make the workflow report that no calls were found even though calls exist. By default it analyzes the 5 most recent matching calls; raise the workflow's maximum-calls-to-analyze input for deeper coverage. Generating a new key pair in Gong invalidates the credentials Serval has stored. Rotation happens entirely in Gong - there is no rotate button in Serval. After rotating, edit the Serval connection and enter both the new Access Key and the new Secret Key. On the edit form, the Access Key and Secret Key display as bullet characters plus their last 4 characters. Leaving them untouched (or leaving the API Base URL blank) keeps the stored values, so you can update one field without re-entering the others. To replace a key, use the Replace button or pencil icon next to it and enter the new value. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Gong integration. # Google Workspace Source: https://docs.serval.com/sections/integrations/google-workspace Connect Serval to your Google Workspace tenant to automate IT and admin operations and index Google Drive content for knowledge search. ## About Google Workspace Google Workspace (formerly G Suite) connects Serval to your organization's Google tenant so you can automate day-to-day IT and admin tasks - managing users, groups, aliases, calendar resources, and more - directly from Serval workflows. It also lets Serval index your Google Drive content so it can be searched as a knowledge source. You can connect using one of three methods, and which one you choose determines what Serval can do. Standard OAuth ("Sign in with Google") is enough for basic user and group management. A Service Account with domain-wide delegation unlocks Knowledge Base (Drive) sync and Gmail delegation in addition to everything OAuth supports. Your own OAuth app uses a client you register in your own Google Cloud project, which reaches Docs, Sheets, Forms, Drive, and Calendar without domain-wide delegation. **Authentication:** OAuth 2.0 (Sign in with Google) for basic user/group management, your own OAuth app for document and calendar work without impersonation, or a Service Account with domain-wide delegation for full capabilities including Drive knowledge sync and Gmail delegation. **Data sync:** Background sync of users, groups, and group members on a recurring schedule; Drive content is indexed continuously on connections granted a Drive scope. Automation and provisioning workflows run on demand. ## What the Google Workspace integration enables | Capability | Description | | - | - | | User sync | Syncs your Google Workspace users into Serval on a recurring schedule, so they're available for assignments, lookups, and workflows. | | Group sync | Syncs Google Groups and their members. Each group carries a single "member" entitlement (Member access to that group). A full sync runs every 16 hours, with an incremental sync every 4 hours. | | Group access provisioning | Adds and removes users to and from Google Groups, so access changes can be automated through Serval workflows. | | Knowledge Base sync | Needs a Drive scope, so it works with a service account or with your own OAuth app, but not with Sign in with Google. Indexes your Google Drive content so it can be searched as a knowledge source. On a service account, knowledge sync uses direct impersonation rather than the standard OAuth path. | | Admin and automation workflows | Manages users, groups, aliases, group settings, calendar resources, mobile devices, contact delegation, and more, depending on the scopes you grant. | | Gmail delegation | Service account only. Manages Gmail delegation and settings. Requires domain-wide delegation. | | Offboarding | Archives a leaver's account onto an Archived User license, transfers their Google Drive files to another user, and reassigns or removes product licenses. Drive transfer and license management need the `admin.datatransfer` and `apps.licensing` scopes and must run as a Google Workspace admin: use a service account, or your own OAuth app authorized by an admin (see [Optional add-on scopes](#optional-add-on-scopes)). | Anything available in the [Google Workspace API](https://developers.google.com/workspace) can be accessed through Serval, as long as the matching scopes are granted. ## Save workflow attachments to Drive Workflows can save Serval attachments, including signed PDFs, to a Google Drive folder. Ask Catalyst to add an upload step to your workflow and provide the destination folder. The workflow can use the attachment returned by an earlier step and preserve its filename. Your Google Workspace connection needs a Drive scope that permits creating files and write access to the destination folder. The standard user and group management scopes alone do not grant Drive upload access. ## Get your credentials How you set up credentials depends on the connection method you choose. Use the Service Account method for Gmail delegation, or for Knowledge Base (Drive) sync across every user's Drive. First, create a Google Cloud project and service account. Then authorize domain-wide delegation and choose one credential path: * Let Serval impersonate the service account without a key. This is the default for Serval Cloud. * Create a JSON key. Self-hosted deployments require this path, and Serval Cloud also supports it. ### Before you start Service account setup uses two separate admin systems: * A **Google Workspace super admin** must authorize domain-wide delegation. * A **Google Cloud project administrator** must create and configure the service account. * A **Google Cloud Organization Policy Administrator** (`roles/orgpolicy.policyAdmin`) is required only when Domain Restricted Sharing blocks Serval's external principal. The JSON key path avoids this policy change. Open the [Google Cloud Console](https://console.cloud.google.com) and select or create the project that will own the integration. Go to **IAM & Admin → Service Accounts**, then create a service account. You don't need to grant project-level roles during creation. In the same project, go to **APIs & Services → Library**. Enable the APIs required for the features you plan to use: * **Admin SDK API** for user and group management * **Google Drive API** for Drive and Knowledge sync * **Google Sheets API** for Sheets export * **Gmail API** for Gmail delegation * **IAM Service Account Credentials API** for both Serval-managed impersonation and the JSON key path New API settings can take 5-10 minutes to propagate. If a newly enabled API still reports an error, wait a few minutes and retry. Serval's regional service account is an external principal. **Domain Restricted Sharing** (`iam.allowedPolicyMemberDomains`) blocks external principals from IAM grants, so we need to add Serval's customer ID to the policy before we can grant access. This requires the **Google Cloud Organization Policy Administrator** role (`roles/orgpolicy.policyAdmin`) on the project, or help from someone who has it. 1. Open [Google Cloud Organization Policies](https://console.cloud.google.com/iam-admin/orgpolicies/list). 2. Select the project that owns the service account in the resource picker. 3. Open **Domain Restricted Sharing** (`iam.allowedPolicyMemberDomains`), then click **Manage policy**. 4. Select **Override parent's policy**, then click **Add a rule**. 5. Under **Policy values**, select **Custom**. Under **Policy type**, select **Allow**. 6. Keep every existing allowed value, including your own Google Workspace customer ID, and add: ```text theme={null} is:C04gvbkuc ``` 7. Save the policy and wait several minutes for it to propagate. Don't replace your existing allowed values. A project-level override replaces the inherited list, so omitting your own customer ID can block principals from your organization. Adding Serval's customer ID only makes Serval principals eligible for IAM grants in this project. It doesn't grant access by itself. Without this exception, Google rejects the grant in the next step with: ```text theme={null} IAM policy update failed One or more users named in the policy do not belong to a permitted customer. ``` If you can't change the organization policy, skip the next step and use the JSON key path. Install and initialize the `gcloud` CLI using Google's [installation instructions](https://docs.cloud.google.com/sdk/docs/install-sdk): ```bash theme={null} gcloud init ``` Inspect the effective policy for the project: ```bash theme={null} gcloud org-policies describe iam.allowedPolicyMemberDomains \ --project=PROJECT_ID \ --effective \ --format=yaml ``` Create `domain-restricted-sharing.yaml`. Copy every existing `allowedValues` entry from the effective policy, then add Serval's customer ID: ```yaml domain-restricted-sharing.yaml theme={null} name: projects/PROJECT_ID/policies/iam.allowedPolicyMemberDomains spec: rules: - values: allowedValues: - EXISTING_ALLOWED_VALUE - is:C04gvbkuc ``` Repeat the `EXISTING_ALLOWED_VALUE` line for every value in the effective policy. Replace `PROJECT_ID` with the project that owns the service account. Apply the project-level override: ```bash theme={null} gcloud org-policies set-policy domain-restricted-sharing.yaml ``` Run the `describe` command again without changing its arguments. Confirm that the effective policy contains every original value and `is:C04gvbkuc`. The CLI path requires the same **Organization Policy Administrator** role as the console path. Applying an incomplete `allowedValues` list can block principals from your organization. Go to **IAM & Admin → Service Accounts**, select your service account, then open **Permissions → Grant access**. Under **New principals**, add Serval's service account email for your region. Assign the **Service Account Token Creator** role. **US region** (`app.serval.com`) - copy and paste exactly: ``` serval@serval-424322.iam.gserviceaccount.com ``` **EU region** (`app.eu1.serval.com`) - copy and paste exactly: ``` serval-eu1@serval-424322.iam.gserviceaccount.com ``` Don't grant the US principal to an EU-hosted organization or the EU principal to a US-hosted organization. Each region signs with its own identity, so a cross-region grant can't mint tokens. Check your Serval address if you aren't sure which region you use. Don't enter your own service account's email here. The principal must be Serval's service account for your region. Self-hosted deployments use the JSON key path. On Serval Cloud, this path is an alternative when Domain Restricted Sharing blocks Serval's principal. Go to **IAM & Admin → Service Accounts**, select your service account, then open **Keys → Add key → Create new key → JSON**. Download the key. You'll upload it in the Serval connect form. Next, open **Permissions → Grant access** on the same service account. Enter the service account's own email under **New principals**, then assign **Service Account Token Creator**. You can also create the self-grant with `gcloud`: ```bash theme={null} gcloud iam service-accounts add-iam-policy-binding YOUR_SA_EMAIL \ --member="serviceAccount:YOUR_SA_EMAIL" \ --role="roles/iam.serviceAccountTokenCreator" ``` Once a key is on file, Serval calls Google as your service account. The self-grant authorizes token minting, and a Token Creator grant to Serval's principal has no effect on this path. The IAM Service Account Credentials API must remain enabled. Both the domain-wide delegation entry and the Serval **Scopes** field must contain `https://www.googleapis.com/auth/cloud-platform`. If **Create new key** is unavailable, an organization policy prevents service account key creation. A Google Cloud administrator must permit key creation or configure Serval-managed impersonation. Open **IAM & Admin → Service Accounts**, select your service account, then open **Details**. Copy the numeric **Unique ID / Client ID**, a long number such as `116634191637610572786`. You'll use it in Google Admin. Open the [Google Workspace Admin Console](https://admin.google.com). Go to **Security → Access and data control → API controls → Manage Domain Wide Delegation**, then click **Add new**. Enter the numeric Client ID from the previous step. Select scopes to authorize. Use **All Scopes** for the full range of Serval capabilities (user and group sync, Drive Knowledge sync, Gmail delegation, calendar, and Sheets). Use **Minimal Directory-Only Scopes** if you only need basic user and group management (no Drive Knowledge sync or Gmail delegation). ```text All Scopes (Recommended) theme={null} https://www.googleapis.com/auth/admin.directory.user https://www.googleapis.com/auth/admin.directory.group https://www.googleapis.com/auth/admin.directory.group.member https://www.googleapis.com/auth/admin.directory.domain.readonly https://www.googleapis.com/auth/apps.groups.settings https://www.googleapis.com/auth/gmail.settings.basic https://www.googleapis.com/auth/gmail.settings.sharing https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.metadata https://www.googleapis.com/auth/spreadsheets https://www.googleapis.com/auth/spreadsheets.readonly https://www.googleapis.com/auth/cloud-platform ``` ```text Minimal Directory-Only Scopes theme={null} https://www.googleapis.com/auth/admin.directory.user https://www.googleapis.com/auth/admin.directory.group https://www.googleapis.com/auth/admin.directory.group.member https://www.googleapis.com/auth/admin.directory.domain.readonly https://www.googleapis.com/auth/cloud-platform ``` **Comma-separated (copy/paste into Google Admin and the Serval Scopes field):** ```text All Scopes (Recommended) theme={null} https://www.googleapis.com/auth/admin.directory.user,https://www.googleapis.com/auth/admin.directory.group,https://www.googleapis.com/auth/admin.directory.group.member,https://www.googleapis.com/auth/admin.directory.domain.readonly,https://www.googleapis.com/auth/apps.groups.settings,https://www.googleapis.com/auth/gmail.settings.basic,https://www.googleapis.com/auth/gmail.settings.sharing,https://www.googleapis.com/auth/calendar,https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/drive.metadata,https://www.googleapis.com/auth/spreadsheets,https://www.googleapis.com/auth/spreadsheets.readonly,https://www.googleapis.com/auth/cloud-platform ``` ```text Minimal Directory-Only Scopes theme={null} https://www.googleapis.com/auth/admin.directory.user,https://www.googleapis.com/auth/admin.directory.group,https://www.googleapis.com/auth/admin.directory.group.member,https://www.googleapis.com/auth/admin.directory.domain.readonly,https://www.googleapis.com/auth/cloud-platform ``` Paste the comma-separated scopes into the OAuth scopes field, then click Authorize. Use the **exact same** comma-separated string in the Serval connect form (see [Connect in Serval](#connect-in-serval)). Enter the numeric Client ID, not the service account's email address. Using the email is the single most common setup mistake. Use one delegation entry per Client ID. `https://www.googleapis.com/auth/cloud-platform` is required in every scope set. Serval relies on it to mint tokens, and Google rejects token creation if it's missing from the Admin delegation grant. For background, see Google's guides on [controlling API access with domain-wide delegation](https://support.google.com/a/answer/162106), [creating and managing service account keys](https://cloud.google.com/iam/docs/keys-create-delete), and [service account impersonation](https://cloud.google.com/iam/docs/service-account-impersonation). The delegation screen Serval links to on validation errors is [Manage Domain-Wide Delegation](https://admin.google.com/ac/owl/domainwidedelegation). There is nothing to create in Google Cloud for the OAuth method. You simply authorize Serval through "Sign in with Google." Begin connecting the Google Workspace integration in Serval and choose the OAuth method. You'll be redirected to Google to sign in and approve the requested access. Serval forces a consent prompt so a refresh token is always issued, even if you've authorized before. After you sign in, Serval determines your Workspace ID automatically and verifies it against the domain you entered in the connect form. Tokens are refreshed automatically as needed. Sign in with Google supports basic user and group management. It can't perform Knowledge Base (Drive) sync or Gmail delegation. For Knowledge sync, connect your own OAuth app with a Drive scope, or use a Service Account; Gmail delegation needs a Service Account. Create an OAuth client in your own Google Cloud project to use Docs, Sheets, Forms, Drive, or Calendar without domain-wide delegation. ### Before you start * A **Google Cloud project administrator** creates the OAuth client. * The person who authorizes the connection must have a Google Workspace account in the domain you enter. Serval uses that account's permissions and the scopes you grant; it cannot impersonate other users. Start connecting the Google Workspace integration in Serval, choose **Your own OAuth app**, and copy the redirect URI shown at the top of the form. Google matches this value exactly, so copy it rather than typing it. The redirect URI is served at a public HTTPS address of your Serval deployment. If the form says your deployment doesn't have one configured, this connection method isn't available there yet; use **Sign in with Google** or a Service Account instead. In Google Cloud Console, go to **APIs & Services → OAuth consent screen** and set the user type to **Internal**. This restricts the app to your own Workspace, so Google requires no brand verification or Cloud Application Security Assessment (CASA). Go to **APIs & Services → Credentials → Create credentials → OAuth client ID**, choose **Web application**, and paste the redirect URI from step 1 into **Authorized redirect URIs**. Save the client ID and client secret. In **APIs & Services → Library**, enable each API the connection needs, such as Google Docs, Google Sheets, Google Forms, Google Drive, and Google Calendar. Google refuses a scope whose API isn't enabled on the project, often with a generic error. If your Workspace restricts third-party app access, a super admin must also trust this client in **Google Admin → Security → Access and data control → API controls**. Until then, sign-in fails with `Error 400: access_not_configured`. * **Knowledge Base sync** indexes only Drive files the authorizing account can access. * **Calendar** access covers the authorizing account's own calendar and calendars shared with it. The built-in **Manage Google Calendar Access** workflow requires a service account. A workflow that calls the Calendar API directly can change sharing if the connection has a sharing scope, such as `calendar` from the **Calendar** preset, and the account has **Make changes and manage sharing** on that calendar. * **Directory sync** requires a Google Workspace admin and directory read scopes. Use the **Directory (read-only)** preset for users, groups, and domains; the domains scope ensures sync recognizes every domain in your Workspace. Serval lists workflows even when the connection lacks their required scopes, so a listed workflow can still fail when run. ## Connect in Serval The connect form differs depending on the method you chose. Required. Your Workspace domain. If left empty, Serval rejects the form with the error `workspaceDomain is required`. Required. The target service account that Serval impersonates. This is your service account's email - not the `client_email` from the JSON key. If left empty, Serval rejects the form with `serviceAccountEmail is required`. This value is shown again when you edit the connection so it round-trips into the form. Required. An admin user in your domain (for example, [admin@company.com](mailto:admin@company.com)) that Serval impersonates. If left empty, Serval rejects the form with `defaultSubject is required`. Required. Paste the **same comma-separated scope list** you authorized in Google Admin domain-wide delegation. If left empty, Serval rejects the form with `scopes are required`. **All Scopes (recommended)** - copy/paste: ``` https://www.googleapis.com/auth/admin.directory.user,https://www.googleapis.com/auth/admin.directory.group,https://www.googleapis.com/auth/admin.directory.group.member,https://www.googleapis.com/auth/admin.directory.domain.readonly,https://www.googleapis.com/auth/apps.groups.settings,https://www.googleapis.com/auth/gmail.settings.basic,https://www.googleapis.com/auth/gmail.settings.sharing,https://www.googleapis.com/auth/calendar,https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/drive.metadata,https://www.googleapis.com/auth/spreadsheets,https://www.googleapis.com/auth/spreadsheets.readonly,https://www.googleapis.com/auth/cloud-platform ``` **Minimal Directory-Only** (user/group sync only, no Drive Knowledge or Gmail delegation): ``` https://www.googleapis.com/auth/admin.directory.user,https://www.googleapis.com/auth/admin.directory.group,https://www.googleapis.com/auth/admin.directory.group.member,https://www.googleapis.com/auth/admin.directory.domain.readonly,https://www.googleapis.com/auth/cloud-platform ``` Serval automatically appends `https://www.googleapis.com/auth/cloud-platform` when it requests tokens, but Google's delegation layer still rejects token creation unless that scope is also explicitly present in your Google Admin delegation grant. Optional on Serval Cloud, US and EU regions (leave it empty for keyless impersonation, or upload your own key - see the JSON key step under [Get your credentials](#get-your-credentials)). Effectively required on self-hosted (unless your operator pre-loaded the key). Paste or upload the JSON key file for your service account. Serval validates it and will reject: * An empty value: `serviceAccountJson is required` * Invalid JSON: `serviceAccountJson is not valid JSON` * The wrong type: `serviceAccountJson must have type="service_account"` * A missing client email: `serviceAccountJson is missing client_email` * A missing or malformed private key: `serviceAccountJson is missing or malformed private_key` The `serviceAccountJson is required` error fires only when no key resolves from any source - the key you submit, then (when editing) the key already on file, then your deployment's platform-level key - so on Serval Cloud, where the platform-level key is configured in both regions, leaving this field empty does not trigger it. If you do upload a key, make sure it is the service account's key file - it starts with `{"type": "service_account", ...}` - not the OAuth client JSON. On edit, the stored key is never shown back - you'll see an empty field with a "key on file" indicator. Leaving it empty keeps the existing key. To rotate the key, paste or upload a new one. Uploading a key on Serval Cloud switches Serval to calling Google as your own service account - make sure the service account holds **Service Account Token Creator** on itself, or token minting fails with an impersonation 403. When you connect or update, Serval validates the impersonation chain end-to-end against Google before saving and surfaces Google's real error verbatim (plus a link to the delegation screen). Trust this connect-time error text - background knowledge sync does not surface configuration errors and can appear as a silent, stalled spinner. You can have Catalyst walk this setup with you. Paste this into a Catalyst session: ```text theme={null} I am connecting Google Workspace to Serval with a service account, using the JSON key path. Walk me through verifying each step: the Admin SDK and IAM Service Account Credentials APIs are enabled, the service account has roles/iam.serviceAccountTokenCreator granted on itself, the domain-wide delegation entry uses the numeric client ID and includes https://www.googleapis.com/auth/cloud-platform, and the Serval connect form has the Workspace domain, service account email, a Default subject that is a real admin user, the same comma-separated scope list, and the uploaded JSON key. Then help me run the connection health checks and interpret any error verbatim. Never ask me to paste the contents of the key file or any other secret. ``` Required. Your Workspace domain. If left empty, Serval rejects the form with `workspaceDomain is required`. Authorize Serval through Google's sign-in flow. After sign-in, Serval determines your Workspace ID automatically and verifies it against the domain you entered. Required. Your Workspace domain. The account that signs in must belong to this domain, and Serval rejects a sign-in from anywhere else. Required. The credentials from the OAuth client you created. On a later reconnect, leave **Client Secret** empty to keep the stored one. If you change the client ID, you must supply a secret as well, since the stored secret belongs to the previous client. Required. Pick the presets you need, or paste scopes one per line. Every scope you list must also appear on your OAuth client's consent screen. A re-consent grants exactly what's listed, so removing a scope revokes it. Optional. Defaults to the domain. Name it to connect more than one Google Workspace integration for the same domain. Authorize the connection. Serval checks that the signing-in account belongs to the domain you entered, records the scopes Google actually granted, and refreshes the token automatically using your client credentials. ## Verifying the connection Before connecting in Serval, confirm these setup steps are complete: | Component | Verification | | - | - | | **APIs enabled** | Google Cloud Console → APIs & Services → Enabled APIs (Admin SDK, Drive, Sheets, Gmail, IAM Service Account Credentials) | | **Serval Cloud Token Creator** | Your service account → Permissions → your region's Serval principal (US: `serval@serval-424322.iam.gserviceaccount.com`; EU: `serval-eu1@serval-424322.iam.gserviceaccount.com`) has **Service Account Token Creator**. If you uploaded a JSON key instead, verify the service account has **Service Account Token Creator** on itself | | **Domain-wide delegation** | Google Admin → Security → API controls → your service account's numeric Client ID is listed with the matching scope set | After connecting, run the health checks - especially the first one - to confirm everything is working. * **Test Google Workspace Connection** verifies Serval can authenticate with Google. On success: `Successfully authenticated with Google Workspace Admin API`. On failure: `Unable to connect to Google Workspace. Please verify your OAuth token or service account credentials are valid and have the necessary Admin SDK API access.`, or, when the Admin SDK API is turned off in the Google Cloud project behind the connection, `The Admin SDK API is not enabled in the Google Cloud project behind this connection, so user and group sync will fail until it is enabled there.` * **List Google Workspace Users** lists a small sample of users. On success: `Successfully listed users from Google Workspace (sample size: N)`. On failure: `Unable to list users from Google Workspace. Please verify your credentials have the 'admin.directory.user' or 'admin.directory.user.readonly' scope.` * **List Google Workspace Groups** lists a small sample of groups. On success: `Successfully listed groups from Google Workspace (sample size: N)`. On failure: `Unable to list groups from Google Workspace. Please verify your credentials have the 'admin.directory.group' or 'admin.directory.group.readonly' scope.` * **Test Google Drive API Access** checks Drive access used for Knowledge Base sync. On success: `Successfully accessed Google Drive API (sample files found: N)`. On failure it begins with `Unable to access Google Drive API.` followed by a branch-specific explanation. * **List Google Shared Drives** checks access to Shared Drives (Team Drives). On success: `Successfully listed Shared Drives from Google Workspace (found: N)`. On failure it begins with `Unable to list Shared Drives.` followed by a branch-specific explanation. On a connection made with your own OAuth app, **List Google Workspace Users** and **List Google Workspace Groups** fail unless the authorizing account is a Google Workspace admin with the directory scopes granted, because both read the Admin Directory. Treat those failures as a statement about directory access, not about the connection. If you didn't grant a directory scope, **Test Google Workspace Connection** confirms the sign-in instead and passes, naming the authorizing account. If you did, it fails when the authorizing account can't read the directory, for example after losing its admin role, or when the Admin SDK API isn't enabled in your Cloud project, because user and group sync will fail too. The two Drive checks show `Skipped` when you didn't grant a Drive scope. If user sync works but the Drive health checks fail, this is usually expected for Service Account connections - and not a real problem. The two Drive health checks run through Serval's OAuth proxy infrastructure, which doesn't carry the service account impersonation context that the actual Knowledge sync uses. As a result, a Drive health check can fail even when Knowledge sync is working perfectly. The failure messages themselves tell you to ignore the result if Knowledge sync is working. ## Scope reference Use this table to customize your scope set. All scopes are prefixed with `https://www.googleapis.com/auth/`. ### Admin Directory | Scope | Description | | - | - | | `admin.directory.user` | Manage users in your domain | | `admin.directory.group` | Manage groups in your domain | | `admin.directory.group.member` | Manage group memberships | | `admin.directory.domain.readonly` | Read domain information | | `apps.groups.settings` | Manage group settings | ### Gmail | Scope | Description | | - | - | | `gmail.settings.basic` | Manage basic Gmail settings | | `gmail.settings.sharing` | Manage Gmail delegation settings | ### Calendar | Scope | Description | | - | - | | `calendar` | Full access to Google Calendar | ### Drive and Knowledge Base | Scope | Description | | - | - | | `drive` | Full access to Google Drive files. Required for Knowledge Base sync. | | `drive.metadata` | Access to file metadata for change detection. Required for incremental Knowledge sync. | ### Sheets | Scope | Description | | - | - | | `spreadsheets` | Full access to Google Sheets | | `spreadsheets.readonly` | Read-only access to Google Sheets | ### Platform | Scope | Description | | - | - | | `cloud-platform` | Required. Enables Serval to impersonate your service account. | ### Optional add-on scopes Add these to the All Scopes list (in both Google Admin and Serval) only if you use the corresponding installable workflows: | Scope | Needed for | | - | - | | `admin.directory.user.alias` | Create, delete, or list user aliases | | `admin.directory.device.mobile` and `admin.directory.device.mobile.action` | Approve pending mobile devices | | `admin.directory.resource.calendar` | Manage calendar resources (rooms/equipment) | | `admin.contact.delegation` | Contact delegation admin | | `admin.directory.rolemanagement` | Read and manage admin roles and role assignments | | `admin.datatransfer` | Transfer Google Drive ownership from one user to another and check data transfer status | | `apps.licensing` | Assign or remove Google Workspace product licenses, including Archived User SKUs | Archiving and unarchiving a user (the **Archive Google User** and **Unarchive Google User** workflows) goes through the Directory API and needs only `admin.directory.user`, which is already in every scope set. Google places the archived account on an Archived User license automatically, so your Workspace must have Archived User licenses available. ## Gotchas and troubleshooting Your scope list must be granted in two independent places that mirror each other: the Google Admin domain-wide-delegation entry **and** the Scopes field in Serval. Both must include `https://www.googleapis.com/auth/cloud-platform`. Serval auto-appends this scope when minting tokens, but Google's delegation layer still rejects the request unless it's explicitly present in the Admin grant. Minimal scope sets that omit cloud-platform will fail. In Google Admin → Manage Domain Wide Delegation, the Client ID field must contain the service account's numeric Unique ID / Client ID (for example, 116634191637610572786), not its email address. Using the email is the single most common setup mistake. Use one delegation entry per Client ID. Errors like `unauthorized_client`, `not authorized for any of the scopes requested`, or `Client is unauthorized to retrieve access tokens using this method` mean the delegation scopes don't match. Fix it by granting the full scope set (including cloud-platform) in the Google Admin domain-wide-delegation entry against the numeric Client ID. Serval surfaces this error from the token-minting step along with a link to the delegation screen. Both messages come from the same token-impersonation step. Workflow and API requests surface Google's verbatim error (for example `impersonate: status code 403: ...` referencing the IAM Service Account Credentials API); some Serval logs and status surfaces still show the generic `failed to generate credentials for Google impersonated service account` wording. Either way, this points to one of: a missing cloud-platform scope, a missing "Service Account Token Creator" role on the target service account, or the IAM Service Account Credentials API not being enabled. Confirm cloud-platform is in your scope list, the required API is enabled in your Google Cloud project, and the correct principal has **Service Account Token Creator** on your service account. On Serval Cloud keyless setups, that principal is Serval's service account for your region (US: `serval@serval-424322.iam.gserviceaccount.com`; EU: `serval-eu1@serval-424322.iam.gserviceaccount.com`). If you uploaded a JSON key, it's your service account itself (the self-grant) - once a key is on file, grants to Serval's principal no longer apply. Enable the Admin SDK API in your Google Cloud project (APIs & Services → Library). Note that newly enabled APIs can take a few minutes to propagate. Directory calls (users and groups) and Drive/Knowledge calls authenticate through different paths. The Drive health checks also route through Serval's OAuth proxy, which lacks the service account impersonation context the real Knowledge sync uses - so those checks can fail (with messages mentioning `SERVICE_DISABLED`, a 403/Forbidden, or a 401/unauthorized) even though Knowledge sync works. The failure messages tell Service Account users to ignore the result if Knowledge sync is working. If a Drive message references the OAuth proxy project, that's a Serval-platform concern and not something you can fix in your own Google Cloud project. When you connect or update, Serval runs full impersonation validation against Google before saving and shows Google's real error verbatim plus a link to the delegation screen. Background knowledge sync does not surface these errors - a misconfiguration there shows only as a stalled spinner. Always run the health checks (especially Test Google Workspace Connection) right after connecting, and trust the connect-time validation text over a stuck sync. Serval always mints an impersonated token during validation (which catches delegation scope problems, target service account existence, the Token Creator role, and IAM API enablement). It additionally probes the directory for your default subject only when a directory scope (preferring `admin.directory.user.readonly`, otherwise `admin.directory.user`) is in your submitted list. Drive-, Gmail-, or Calendar-only connections are not forced to add a directory scope just to pass validation. The group readonly scope does not satisfy this probe. On Serval Cloud, the Service Account Key (JSON) field is optional - by default Serval signs with its own regional deployment service account and impersonates your target service account via the Token Creator role. Uploading your own JSON key is also supported on Serval Cloud: Serval then calls Google as your service account, which must hold **Service Account Token Creator** on itself (grants to Serval's principal stop applying once a key is on file). The key path is useful when the Domain Restricted Sharing policy blocks adding external principals. On self-hosted, the JSON key is effectively required unless your operator pre-loaded the cluster secret for it. When editing a connection, Serval never echoes the stored JSON key - you'll see an empty field with a "key on file" indicator. Leaving it empty keeps the existing key; paste or upload a new key to rotate. The JSON's client email (your source service account) is never used to overwrite the Service Account email field (your target service account). If you connected with Sign in with Google and want to restart the authorization from scratch, delete the connection on both sides. In Serval: open Integrations, select your Google Workspace connection, and delete it (other data is retained if you reconnect later). On the Google side: sign in to the Google account that authorized the connection, open Manage your Google Account, go to Security, then Connections to third-party apps and services, select Serval, and delete all connections. Reconnecting afterwards walks through the full authorization flow as if connecting for the first time. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Google Workspace integration. # Granola Source: https://docs.serval.com/sections/integrations/granola Connect your Granola workspace to Serval so workflows can read AI meeting notes, summaries, and full transcripts on demand. ## About Granola Granola is an AI meeting-notes product that captures meetings and produces notes, summaries, and transcripts. The Serval integration connects your Granola workspace with a Granola API key, giving Serval workflows read-only access to your meeting notes through Serval's authenticated proxy. Workflows can list notes, filter them by date, and pull the full detail of any meeting, including attendees, calendar details, AI summaries, and the word-by-word transcript. **Authentication:** API key - a single Granola API key pasted into the connect form. Serval stores it securely and attaches it to every request automatically; the key is only ever sent to Granola's API host, and workflow code never sees it. **Data sync:** On demand only - workflows read from Granola at run time. There is no background sync, no webhooks, and no pre-built installable workflows. ## What the Granola integration enables | Capability | Description | | - | - | | List meeting notes | Pull meeting notes in pages, with each entry showing the note's title, owner, and when it was created and last updated. Lists can be filtered to notes created before or after a given time, or updated after a given time. | | Fetch a full note with its transcript | Retrieve everything Granola captured for one meeting: attendees, calendar event details (title, invitees, organizer, scheduled start and end), folder membership, the AI summary in both plain-text and formatted form, and the transcript - each line tagged with its speaker source (microphone or speaker) and timestamps. | | Read-only workflow access | Workflows get typed, read-only access to Granola data through Serval's authenticated proxy. Reading notes, summaries, and transcripts is supported; creating, updating, or deleting notes is not. | Anything in the integration's modeled surface of the [Granola API](https://docs.granola.ai/api-reference) can be accessed through Serval. ## Get your credentials You need a Granola API key, created from the Granola desktop app. Keys start with `grn_`. Per the [Granola API overview](https://docs.granola.ai/introduction), any workspace member on a Business plan can create API keys; on Enterprise plans, a workspace admin chooses which access scopes members can use. In the Granola desktop app, open Settings, then Connectors, then API keys. Click Create new key and choose the note access scopes the key should include - Personal notes, Public notes, or both. These scopes decide which notes Serval workflows will be able to read. Click Generate API Key, then copy the key (it starts with `grn_`) and store it securely. On Enterprise plans, a workspace admin controls which API access scopes members can use, under Settings, then Workspace, then General, then API access for members. If you cannot create a key or select a scope, ask a workspace admin to enable API access first. ## Connect in Serval In Serval, open the **Granola** integration and start a new connection. Paste the key into the **API Key** field. It is a password field, so the value is hidden as you type. The helper text under the field reads: "Your Granola Enterprise API key. Generate one from Settings → Workspaces → API tab." Click **Submit**. The form does not validate the key at save time - a mistyped or blank key is accepted silently and only surfaces when the health check below runs. The helper text points at an older location in Granola's settings. In current Granola versions, API keys live under Settings, then Connectors, then API keys, as described above. When you reopen the connection settings later, the saved key is shown masked - bullet characters plus its last 4 characters - and it cannot be typed over directly. Only save the settings when you are rotating the key. To rotate, select the pencil icon (or **Replace** button) next to the masked value, paste the complete new key, and save in the same edit. Never save while the key field is empty, and if you opened the settings without meaning to change the key, close them without saving. ## Verifying the connection The Granola integration includes one health check, **List Granola Notes**. It uses your stored key to list a single note from your workspace, confirming Serval can reach the Granola API on your behalf. * On success: "Successfully connected to Granola. Found 1 note(s)." The number is how many notes the check retrieved - at most one, and a brand-new workspace with no notes yet can show 0, which still counts as success. * On failure: "Unable to list Granola notes. Please verify your API key is valid and you have Enterprise plan access." If the health check is green but a workflow that reads many notes fails intermittently, it may be hitting Granola's rate limits. Have the workflow read notes in smaller pages and retry after a pause instead of re-running immediately. ## Gotchas and troubleshooting On the edit screen the saved key appears masked - bullets plus its last 4 characters - and cannot be typed over directly. To rotate it, select the pencil icon (or **Replace** button) next to the masked value; this clears the field so you can paste the complete new key. Paste the full key and save in one step - never save while the field is empty. If the connection fails right after an edit, re-enter the complete key and save again. Neither the connect form nor Serval validates the key when you save - a mistyped or empty key is accepted silently and only surfaces later as a failing List Granola Notes health check. Always run the health check right after connecting or editing. The health check's failure message asks you to verify Enterprise plan access, and the connect form calls the credential a Granola Enterprise API key. Per Granola's current API documentation, API keys are also available on Business plans, with Enterprise workspace admins controlling which access scopes members can use. If the check fails, the most common causes are a mistyped or revoked key, or a key created without a usable access scope - confirm those before debugging your plan. Granola API keys carry note access scopes: Personal notes (notes you own or that are shared with you) and Public notes (notes visible to everyone in the workspace, including the Team space). A workflow can only read notes the key's scopes allow, so a healthy connection can still return fewer notes than you expect. Edit or recreate the key with broader scopes if workflows are missing notes. Workflows can read notes, summaries, and transcripts, but cannot create, update, or delete anything in Granola through this integration. If a workflow needs to write meeting data somewhere, it must write to another system. Granola can rate-limit both listing notes and fetching individual notes. Workflows that read large numbers of notes should page through results gradually and back off when requests are rejected, rather than requesting everything at once. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Granola integration. # Greenhouse Source: https://docs.serval.com/sections/integrations/greenhouse Connect Greenhouse, the applicant tracking system, so Serval workflows can create candidates, manage applications, and list open jobs on demand. ## About Greenhouse Greenhouse is an applicant tracking system (ATS) for managing recruiting pipelines: candidates, applications, interview stages, and jobs. Serval connects to the Greenhouse Harvest API (v3) and calls it on demand from workflows - for example, to create a candidate or advance an application to a new stage. This integration covers the Harvest v3 surface only; Job Board, webhooks, and Greenhouse Onboarding are not included. **Authentication:** OAuth 2.0 client credentials - a Client ID and Client Secret from a Greenhouse Harvest API integration credential. Serval mints a short-lived token for each request automatically. **Data sync:** On demand only. Serval reads or writes Greenhouse data when a workflow step runs. There is no background sync, no entity ingestion, and no webhooks. ## What the Greenhouse integration enables | Capability | Description | | - | - | | Harvest API requests | Workflows call the Greenhouse Harvest v3 API through Serval's typed client. Coverage today is a focused set of endpoints: listing users, listing and creating candidates, creating, advancing, and rejecting applications, and listing jobs, with support for paginated list results. | | Create Candidate | Prebuilt workflow that creates a new candidate from a first and last name, plus optional email, phone number, title, and company. Requires installer approval by default. | | Add Application | Prebuilt workflow that adds a new application to an existing candidate for a specific job, with optional source attribution and starting stage. Requires installer approval by default. | | Advance Application Stage | Prebuilt workflow that moves an application from its current stage to a new stage. Requires installer approval by default. | | Reject Application | Prebuilt workflow that rejects an application with a specified rejection reason, plus an optional rejection email template and internal notes. Requires installer approval by default. | | List Open Jobs | Prebuilt workflow that lists all open jobs, automatically following pagination through every page of results, with an optional requisition ID filter. Runs without approval by default. | The integration exposes a growing slice of the [Greenhouse Harvest API v3](https://harvestdocs.greenhouse.io/reference); additional surfaces are planned as future phases. ## Get your credentials Serval needs a Harvest V3 (OAuth) API credential from Greenhouse. When you create one, Greenhouse automatically provisions an Integration Service User (ISU) for it - by default, every Serval call runs as that user. See the [Greenhouse Harvest API v3 reference](https://harvestdocs.greenhouse.io/reference) for background. Sign in as a user with permission to create and manage API credentials. Go to **Configure > Dev Center > API Credential Management**. Create a new API credential, choose **Harvest V3 (OAuth)** as the credential type, and enter a descriptive name such as "Serval Integration". Save the credential and copy both values. In Greenhouse, make sure the credential's Integration Service User can access the data your workflows will touch - candidates, applications, jobs, and users at minimum. You can adjust this in Greenhouse at any time. If your workflows need elevated access for list endpoints, open a Site Admin user's profile in Greenhouse and copy the numeric user ID from the profile URL. You can enter it as the Authorizing User ID in Serval. Store the Client Secret securely - anyone who has it can request Harvest tokens for your Greenhouse account. Serval's token requests contain no OAuth scopes and Serval has no permission settings of its own. What the integration can read and write is governed entirely by the access Greenhouse grants the credential and its Integration Service User (or the Authorizing User, if you set one). ## Connect in Serval In Serval, add a new Greenhouse integration. **Automatic** keeps your saved region when reconnecting and uses Default for new connections. Select **Default** (`harvest.greenhouse.io`), **EU** (`harvest.eu.greenhouse.io`), or **US** (`harvest.us.greenhouse.io`) to choose a specific region. The dashboard address, such as `s101.recruiting.eu.greenhouse.io`, is not an API address. The OAuth Client ID from your Greenhouse Harvest API integration credential. It also serves as the connection's unique identifier. Leaving it blank shows "This field is required". The OAuth Client Secret for the same credential, entered as a password field. After you connect, Serval never shows it in full again - it displays obfuscated as bullets plus the last 4 characters. A numeric Greenhouse user ID. Use a Site Admin's ID if list endpoints need elevated access; leave blank to run as the Integration Service User. Only digits are accepted - anything else is rejected with an error that includes "Authorizing User ID must be a numeric Greenhouse user ID". Save the form. Serval then verifies the connection with health checks (see below). You can change the API region without re-entering the Client ID or Client Secret. Serval preserves saved credentials when their fields are unchanged. Token requests use `https://auth.greenhouse.io/token` for every API region. ## Verifying the connection After you connect, Serval runs three health checks against your Greenhouse account: * **Test Greenhouse Harvest Connection** - confirms Serval can authenticate to the Harvest API by listing users. Success: "Successfully authenticated with the Greenhouse Harvest API." Failure: "Unable to connect to Greenhouse. Verify that the Client ID and Client Secret are correct and that the Integration Service User has Harvest API permissions." * **List Open Greenhouse Jobs** - verifies the integration can list open jobs by fetching a small sample. Success: "Successfully listed open jobs from Greenhouse (sample size: \[number])." Failure: "Unable to list open jobs from Greenhouse. Verify that the Integration Service User has access to job data." * **List Greenhouse Candidates** - verifies the integration can list candidates by fetching a small sample. Success: "Successfully listed candidates from Greenhouse (sample size: \[number])." Failure: "Unable to list candidates from Greenhouse. Verify that the Integration Service User has access to candidate data." If "Test Greenhouse Harvest Connection" passes but the jobs or candidates checks fail, your credentials are valid but the Integration Service User cannot see that data. Either grant the Integration Service User access to that data in Greenhouse, or set the Authorizing User ID to a Site Admin's numeric Greenhouse user ID so requests run with that user's access. ## Gotchas and troubleshooting Edit the connection and select its API region. Leave the saved Client ID and Client Secret unchanged to keep them. To rotate the secret, use the pencil icon or **Replace** control and enter the new secret before saving. Run the health checks after changing regions or credentials. By default, calls run as the Integration Service User that Greenhouse auto-provisions for the credential, and that user may lack access to job or candidate data. Set the Authorizing User ID to a Site Admin's numeric Greenhouse user ID so Serval makes requests as that user instead. The field accepts only digits - leading and trailing whitespace is trimmed, and any other character is rejected with an error that includes "Authorizing User ID must be a numeric Greenhouse user ID". Use the numeric ID from the Greenhouse user's profile URL, not an email address or name. To go back to running as the Integration Service User, clear the Authorizing User ID field in the connection settings and save. Serval does not send or manage OAuth scopes, and there are no permission toggles on the Serval side. Access is governed entirely by what the credential's Integration Service User (or the Authorizing User, if set) is allowed to do in Greenhouse. If a workflow hits permission errors, adjust the credential's access in Greenhouse's API Credential Management, or point the connection at a different Authorizing User ID. The integration covers the Harvest API v3 surface only. Legacy Harvest v1 calls (including the v1 On-Behalf-Of behavior), the Job Board API, webhooks, and Greenhouse Onboarding are not supported and are planned as future phases. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Greenhouse integration. # Harness (Beta) Source: https://docs.serval.com/sections/integrations/harness Connect Harness to call platform APIs for users, groups, projects, and pipelines from Serval workflows. The Harness integration is in beta. It includes a typed API request action based on Harness's complete platform OpenAPI specification. The connector uses the standard Harness SaaS host, `app.harness.io`. Vanity domains and self-managed Harness installations are not supported by this connection form. ## Connect the integration Open your Harness account and copy the account identifier from its URL. Create an API key and token for a Harness service account. Give it roles and resource groups for only the organizations, projects, and operations your workflows need. The default connection check lists organizations, so it requires permission to view organizations. Open **Integrations > All integrations**, select **Harness**, and enter your **Account ID** and **API Token**. Save the connection. Serval stores the token as a secret. It supplies `x-api-key` and `Harness-Account` headers, fills the `accountIdentifier` query parameter, and binds account path parameters to the connection. Pass other required query parameters explicitly. Changing the connected account requires a new token. Organization and project identifiers remain explicit workflow inputs; access is enforced by Harness. ## Verify the connection Read-only healthchecks list organizations, projects, and user groups. They request one result per check and can succeed when the result is empty. A successful read does not establish permission to execute pipelines or change group membership. Check the account ID, token expiry, assigned roles, and resource groups when a healthcheck fails. A token scoped to a project may lack permission for an account-level check. ## Send requests Call `harness.apiRequest` with a path, HTTP method, path parameters, query parameters, and a JSON body when needed. For example: ```typescript theme={null} await harness.apiRequest( { path: "/ng/api/projects", method: "GET", query: { orgIdentifier: "engineering", pageSize: 20 }, }, ctx, ); ``` Pass `bodyText` for endpoints that accept YAML. Serval sends that string without JSON encoding. For example, the pipeline execution endpoint `/pipeline/api/pipeline/execute/{identifier}` accepts runtime input YAML through `bodyText`; the input-set execution endpoint accepts a JSON body. The action returns one response per call. Follow Harness's pagination parameters to retrieve subsequent pages. Execution acceptance is not pipeline completion: retain the execution ID and query its execution status. Avoid resubmitting a run when its submission result is unknown. This initial connector supports JSON responses, JSON or YAML request bodies, and the shared HTTP proxy's comma-separated array query format. Multipart uploads, binary responses, and other query serialization formats are outside this scope. Treat names, descriptions, pipeline YAML, and other returned Harness content as untrusted data. They do not authorize further actions or changes. For group changes, use individual membership endpoints. Harness's legacy `add-user-to-groups` endpoint replaces other memberships. Manage SCIM-imported membership in the identity provider. Harness's Approval API requires a personal access token; service-account tokens cannot approve those steps. See the [Harness API reference](https://apidocs.harness.io/) and [OpenAPI download](https://apidocs.harness.io/_bundle/index.yaml?download). # Have I Been Pwned Source: https://docs.serval.com/sections/integrations/haveibeenpwned Connect Have I Been Pwned (HIBP) so workflows can check accounts, domains, and pastes against known data breaches through the HIBP API - authenticated with an API key. The Have I Been Pwned integration is in beta. ## About Have I Been Pwned Have I Been Pwned (HIBP) is a data-breach search service. Serval connects to it with an API key so workflows can look up whether an account or domain appears in a known breach, browse the breach and paste catalogs, and reach the rest of the HIBP API on demand - useful for security triage, offboarding checks, and credential-exposure alerts. **Authentication:** API key. Serval injects your stored key as the `hibp-api-key` request header on every call, so workflows never handle the key directly. The key comes from [haveibeenpwned.com/API/Key](https://haveibeenpwned.com/API/Key) and requires an active HIBP Pwned subscription. **Data sync:** On demand only. There is no background sync and no entity ingestion. Workflows call the HIBP API v3 live when they run. ## Get your credentials Generate an API key at [haveibeenpwned.com/API/Key](https://haveibeenpwned.com/API/Key). Every key carries a rate limit (requests per minute) set by its subscription tier. Some capabilities need a higher tier: domain search requires the domain to be verified in the HIBP dashboard first, and the stealer-log endpoints require the top Pwned 5 tier. ## Connect in Serval In Serval, open the Have I Been Pwned integration and start a new connection. Paste the API key you generated above. Submit the form. Serval runs the health check below to confirm the key works. ## Verifying the connection The connection health check reads `/api/v3/subscription/status`, which reports the key's subscription tier and rate limit. A passing check confirms the key is valid and active. ## Gotchas and troubleshooting On lookup endpoints (breached account, breached domain, paste account, and the stealer-log endpoints), HIBP returns **404 when the subject has no results** - that is, the account isn't in any breach. In a workflow, treat a 404 from these endpoints as an empty result rather than an error. Exceeding your key's per-minute rate limit returns 429 with a `retry-after` header. Reduce polling frequency or batch lookups in scheduled workflows, and check `/api/v3/subscription/status` for your tier's limit. Domain search requires the domain to be verified in the HIBP dashboard, and the stealer-log endpoints require the top Pwned 5 tier. If a call fails with an authorization error, confirm your subscription tier covers that endpoint. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Have I Been Pwned integration. # Hevy Source: https://docs.serval.com/sections/integrations/hevy Connect Serval to Hevy with an API key so workflows can read workouts, routines, exercise templates, and profile data from a Hevy Pro account. ## About Hevy Hevy is a workout tracking app for logging strength training. The Serval Hevy integration connects to the Hevy API at `api.hevyapp.com` using an API key from a **Hevy Pro** subscription. Once connected, workflows can read workouts, routines, exercise templates, body measurements, and account info for the authenticated user. The integration is marked **Beta** in Serval's connect UI. **Authentication:** API key sent in the `api-key` HTTP header. Serval stores the key encrypted and attaches it to every request automatically. **Data sync:** On demand only. There is no background sync — workflows fetch Hevy data live when they run. ## What the Hevy integration enables | Capability | Description | | - | - | | Hevy Workouts bundle | Prebuilt workflows to list workouts, fetch a workout by ID, and get the total workout count. | | Hevy Routines bundle | List routines, fetch a routine by ID, and list routine folders. | | Hevy Exercises bundle | List exercise templates, fetch a template by ID, and retrieve exercise history with optional date filters. | | Hevy Profile & Measurements bundle | Read the authenticated user's profile info and list logged body measurements. | | Hevy API request | Typed access to the Hevy API v1 from custom workflows — workouts, routines, exercise templates, and user endpoints supported by your API key. | See Hevy's [developer settings](https://hevy.com/settings?developer) for API key generation requirements. ## Get your credentials You need an active **Hevy Pro** subscription and an API key generated in the Hevy web app. API access requires Hevy Pro. Upgrade in the Hevy app if the developer settings page is unavailable. In the Hevy web app, go to [Settings → Developer](https://hevy.com/settings?developer). Create a new API key and copy it immediately. Use the **API Key** password field in Serval's Hevy connect form. Hevy API keys are tied to the account that created them. Workflows operate on that user's workout data only. ## Connect in Serval In Serval, add the Hevy integration. It is labeled **Beta**. Paste your Hevy API key into the password field. Helper text points to `hevy.com/settings?developer`. Submit the form. Serval runs four health checks against the Hevy API (see below). When editing an existing connection, the stored API key is shown obfuscated. Re-paste the full key to rotate it. ## Verifying the connection Four health checks run after you connect: 1. **Test Connection** — calls `GET /v1/user/info`. Success includes the authenticated user's display name. Failure: `Unable to connect to Hevy. Please verify your API key is valid and that you have an active Hevy Pro subscription.` 2. **List Workouts** — fetches a page of logged workouts. 3. **List Routines** — fetches saved workout routines. 4. **List Exercise Templates** — fetches available exercise templates. If the connection test fails, confirm Hevy Pro is active and regenerate the API key in Hevy developer settings before updating the integration in Serval. ## Gotchas and troubleshooting Without an active Pro subscription, key generation and API calls fail. The connection test message explicitly calls this out. The shipped Hevy workflow bundles read data only. Creating or editing workouts through Serval requires custom workflows that call write endpoints, if Hevy exposes them for your key. Hevy list endpoints return paginated results. Prebuilt list workflows handle paging; custom workflows should follow the API's page parameters until a page returns fewer rows than the limit. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Hevy integration. # HiBob Source: https://docs.serval.com/sections/integrations/hibob Connect Serval to HiBob (Bob), the HR platform, so your workflows can read employee profiles, search people, and check time off on demand. ## About HiBob HiBob (also called Bob) is an HR platform (HRIS) that holds your organization's employee data, profiles, and time off records. Serval connects to a single HiBob account through a HiBob Service User - an API-only account you create in HiBob. Once connected, your Serval workflows can read people data and time off information from HiBob whenever they run. Serval supports both HiBob environments - production (api.hibob.com) and sandbox (api.sandbox.hibob.com). Each connection routes its API calls to the environment you selected when connecting, and credentials are only ever sent to these two HiBob API hosts. **Authentication:** HiBob Service User (a Service User ID and Service User Token, stored together as one credential). There is no OAuth flow. **Data sync:** On-demand only. Workflows call the HiBob API at the moment they run. There is no background sync, no data ingestion, no webhooks, and no event triggers. ## What the HiBob integration enables | Capability | Description | | - | - | | Employee profiles and people data | Read employee profiles and your company's people-field definitions. Employees can be referenced by HiBob's internal ID or by their email address. | | People search | Look up employees by their attributes, for example resolving someone's HiBob ID from their work email so a workflow can act on the right person. | | Time off | Check an employee's remaining time off balance for a specific policy type as of a specific date, and list everyone who is out of the office today. | | Installable workflows | Employee self-service bundles for looking up profiles, finding coworkers, and managing time off (see below). | | Full HiBob API access | Workflows are not limited to the capabilities above - they can reach any part of the HiBob Public API your service user is permitted to use, including areas such as attendance, tasks, documents, reports, and workforce planning. | Anything defined in the [HiBob API](https://apidocs.hibob.com/) can be accessed through Serval. ## Installable workflows Each workflow identifies the requesting employee automatically from their email. | Bundle | Workflows | | - | - | | **Directory** | **Get My HiBob Profile** and **Find a HiBob Coworker** - look up your own profile or a coworker's title, department, site, and manager. | | **Time Off** | **Check My Time Off Balance in HiBob**, **List Who's Out in HiBob**, and **Request Time Off in HiBob**. | Read-only workflows run without approval by default. **Request Time Off in HiBob** writes back to HiBob and requires approval by the installer by default. ## Get your credentials Serval authenticates with a HiBob **Service User**: an API-only account that is not tied to a real employee and cannot log in to Bob. Creating one gives you a Service User ID and a Token, and you control exactly what it can access through a HiBob Permission Group. HiBob's official [API Service Users guide](https://apidocs.hibob.com/docs/api-service-users) covers the same process in more detail. HiBob discontinued its legacy API Access Token method on October 31, 2024. Service Users are the only supported way to connect. Log in to HiBob as an Admin and go to Settings > Integrations > Service Users, then click **Add Service User**. If you don't see the Service Users option, ask your HiBob administrator to grant you the necessary permissions. Give the service user a descriptive name (for example "Serval Integration"), click **Create**, and copy both the Service User ID and the Token right away. The Token is displayed only once. If you lose it, you must regenerate it in HiBob. Go to Settings > Account > Permission Groups and click **Add Permission Group**. Name it something descriptive (for example "Serval API Access"). New service users have no permissions at all by default. Add the service user to the new group, and keep the group scoped to only the permissions your Serval workflows require. Edit the group's permissions. Under **Features**, enable the areas of Bob you need (for example Reports for reporting). Under **People's Data**, grant access per category: "View" permissions for reads, "View histories" for historical data such as lifecycle or work table entries, and "Edit" for updates or sensitive fields. For basic people search access, assign the Default Employee Fields permissions, which cover the root, about, employment, and work categories. Under **People's Data**, use **Access data for** to choose Everyone, Select by condition, or Select by name. By default service users can only access active employees; to include inactive employees, edit the access conditions and remove the "Lifecycle status equals Employed" filter. If your workflows will check time off balances or who is out today, make sure the group also includes Time off API permissions - these are separate from people-data permissions. ## Connect in Serval In Serval, add the **HiBob** integration to open the connect form. **Environment** (required) - select **Production (api.hibob.com)** or **Sandbox (api.sandbox.hibob.com)**. Defaults to Production. Pick the environment the service user was created in: a sandbox service user only authenticates against the sandbox API, and a production service user only against production. **Service User ID** (required) - a text field with the helper text "Your HiBob API Service User ID". If it is left blank, the form shows "This field is required" and will not submit. **Service User Token** (required) - a password field with the helper text "Your HiBob API Service User Token". The form does not check the Token as you type, so paste it carefully; submitting without one fails with the error "Failed to install integration (HTTP 500)". Serval stores the ID and Token together as a single credential and uses it for every call your workflows make to HiBob. The Basic Authentication encoding is handled automatically - enter both values exactly as HiBob displayed them. When you edit an existing connection, the Service User ID appears in full and the Token appears as a masked value - dots plus its last four characters - that you can't type into directly. To enter a new Token, click **Replace** (on the reconnect form) or the pencil icon (on the connection settings page) and paste the new value. Serval keeps your existing credentials whenever the Token is left untouched or either field is blank on save - the credential is replaced only when both fields are filled in. Because the two values are stored together as one credential, an edit that changes only the Service User ID does not take effect; re-enter the Token whenever you change the ID. ## Verifying the connection Serval ships three health checks for HiBob. Each one calls the live HiBob API when it runs. **Test HiBob Connection** - verifies the credential can reach the HiBob API by reading your company's people-field definitions. * Success: "Successfully connected to HiBob API and retrieved \[number] people fields" * Failure: "Unable to connect to HiBob. Please verify your Service User ID and Token have the required permissions." **List HiBob Employee Profiles** - reads employee profiles and reports how many were returned. * Success: "Successfully listed employee profiles from HiBob (count: \[number])" * Failure: "Unable to list employee profiles from HiBob. Please verify your Service User ID and Token have the required permissions." **List HiBob Employees Out Today** - reads the list of employees out of the office today, which specifically exercises the Time off API permission. * Success: "Successfully retrieved time off data from HiBob (\[number] employees out today)" * Failure: "Unable to retrieve time off data from HiBob. Please verify your Service User ID and Token have the required permissions for the Time off API." A service user can pass the connection and profile checks while still failing the out-today check, because Time off API access is a separate permission in HiBob. If only the time off check fails, add Time off permissions to the service user's Permission Group. ## Gotchas and troubleshooting HiBob issues separate service users for production and sandbox, and each one only works against its own host. If every API call fails with a 403 error like "token not match", check that the connection's **Environment** matches where the service user was created - a sandbox service user used with the Production environment (or vice versa) fails this way. Edit the connection, switch the Environment, and re-run the health checks. The environment is part of a connection's identity. If you switch an existing connection from Production to Sandbox (or back), workflows that were bound to the old environment's instance stop resolving it and fail at the start of their next run until you switch back or update the workflow's app binding. If you need both environments at once, keep two separate connections - for example your production connection in your main workspace and a sandbox connection in a testing workspace - instead of flipping one connection back and forth. A freshly created HiBob service user can authenticate but cannot read anything until it is added to a Permission Group with the right category permissions. In Serval this shows up as failing health checks that ask you to verify the Service User ID and Token have the required permissions. Grant the permissions in HiBob, confirm the service user has not been deleted or deactivated, then re-run the health checks. Time off requires its own Time off API permission in HiBob, separate from people-data permissions. A service user can read profiles successfully while every time off call fails - the time off health check failure message calls this out explicitly. Add Time off permissions to the service user's Permission Group. HiBob displays the Service User Token a single time, at creation. Serval stores it masked (dots plus the last four characters) - it can be replaced but never revealed. If the token is lost, regenerate it in HiBob, then update the Serval connection: click **Replace** on the Token field, paste the new Token, and save. There is no automatic token refresh or expiry handling - rotation is always manual through the connection's edit form. The Service User ID stays filled in on the edit form, so replacing just the Token rotates the credential in one step. Leaving either field blank on save keeps your existing stored credentials unchanged, and a change to the Service User ID only takes effect when a Token is entered along with it. HiBob filters a service user's data access to active employees (the "Lifecycle status equals Employed" condition). Workflows that need offboarded or pre-start employees require editing the Permission Group's Access data for conditions in HiBob to remove that filter. People data includes custom fields defined per organization, so the exact field set differs from one HiBob account to another. Employees can also be referenced by either HiBob's internal ID or their email address - helpful to know when a workflow asks for an employee identifier. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your HiBob integration. # HubSpot Source: https://docs.serval.com/sections/integrations/hubspot HubSpot is a CRM and marketing platform; Serval connects to it with a private app access token and calls the HubSpot API on demand from your workflows. ## About HubSpot HubSpot is a CRM and marketing platform covering contacts, companies, deals, tickets, users, and communication preferences. Serval connects to your HubSpot account with a private app access token and calls the HubSpot API only when a workflow or health check runs - anything your private app's scopes cover is reachable through a single generic API request action. There are no prebuilt per-object helpers and no background sync. You will see this integration listed as "Hubspot" in Serval. **Authentication:** HubSpot private app access token, entered in Serval as an "API Key". One long-lived token - no OAuth sign-in and no token refresh. **Data sync:** On demand only. Serval never syncs or polls HubSpot in the background; data is read or written only when a workflow step or health check runs. ## What the HubSpot integration enables | Capability | Description | | - | - | | Call any HubSpot API endpoint | The "Hubspot API request" action sends any request to HubSpot using your stored token. Workflows can read, create, update, and search contacts, companies, deals, and tickets, request specific fields, and page through results up to 100 at a time. | | User and team management | List, create, update, and remove HubSpot users (looked up by user ID or email address), and list roles and teams - including which roles carry a paid seat. | | "Unsubscribe from Marketing Emails" (installable workflow) | Takes a contact's email address, reads their current email subscription statuses, and unsubscribes them from each active subscription type one by one, reporting the result for each. | | "Provision HubSpot User with Core Seat" (installable workflow) | Takes an email, first name, and last name, creates the user in HubSpot with the default core seat, and sends them a welcome email to set their password. | Anything defined in the [HubSpot API](https://developers.hubspot.com/docs/reference/api/overview) can be accessed through Serval. ## Get your credentials Serval authenticates as a HubSpot **private app**. You create the app in HubSpot, grant it the scopes (permissions) your workflows need, and paste its access token into Serval. HubSpot's official walkthrough is the [private apps guide](https://developers.hubspot.com/docs/guides/apps/private-apps/overview). In HubSpot, click **Settings** (the gear icon), then in the left sidebar go to **Integrations**, then **Private Apps**. Click **Create a private app** and give it a name (for example "Serval Integration") and a description. On the **Scopes** tab, grant the scopes your workflows will call. At minimum, for the built-in connection test and the user management capability, grant `settings.users.read`, `settings.users.write`, `settings.users.teams.read`, and `settings.users.teams.write`. Add CRM object scopes if your workflows touch contacts, companies, deals, or tickets, and communication preferences scopes if you plan to install the "Unsubscribe from Marketing Emails" workflow - confirm exact names against HubSpot's scope catalog in the Scopes tab. Click **Create app**, then copy the access token. The built-in connection test reads your account's user settings, so `settings.users.read` is effectively required for the health check to pass. You can add scopes to the private app at any time later. The existing token picks up scope changes automatically - you only need to update the token in Serval if HubSpot rotates it. ## Connect in Serval In Serval, open the Hubspot integration's connect form. "Instance Name" is a free-text label for this connection and becomes its display name. Neither field on this form is marked required, so you will not see an asterisk or a "This field is required" error. "API Key" is a password field for the private app access token. There is no format check and the token is not tested when you submit - a blank or mistyped value saves successfully. After saving, the value is shown masked with only the last 4 characters visible; the integration's settings form offers a pencil icon (and the configure dialog a **Replace** button) to enter a new one. Submit the form, then run the "Test HubSpot Connection" health check right away (see below) - that is the first moment an invalid token will surface. When you edit this connection later for any reason - even just renaming it - you must re-enter the **full** access token in "API Key" before saving. Saving the edit form without retyping the token erases the stored credential and silently breaks the connection. Leaving "Instance Name" blank on an edit is safe (it keeps the existing name); leaving "API Key" untouched is not. When you click the pencil icon to replace the token on the settings form, the emptied field's placeholder reads "Enter new value". ## Verifying the connection The integration ships one health check: * **Test HubSpot Connection** - asks HubSpot to list the users in your account settings using the stored token. On success it reports "Successfully authenticated with HubSpot". On failure it reports "Unable to connect to HubSpot. Please verify your API key is valid and has the necessary scopes." A pass confirms the token is valid and can read user settings - it does not confirm any other scope. If the health check is green but a workflow still fails with a permission error, the private app is missing a scope for that specific call. HubSpot's error response lists the missing scopes - add them to the private app in HubSpot and re-run. You do not need to re-enter the token in Serval. ## Gotchas and troubleshooting The update form does not keep your stored token when the "API Key" field is left masked or blank - saving any change without retyping the full token stores an empty credential and silently breaks authentication. The break shows up as the health check failing with "Unable to connect to HubSpot. Please verify your API key is valid and has the necessary scopes." Always paste the complete token again before saving an edit. Only "Instance Name" is safe to leave blank (it keeps the existing name). The connection test only reads user settings. Workflows that touch CRM records, communication preferences, or user creation can still fail with permission errors if the private app lacks those scopes. HubSpot's error message includes the list of missing scopes - grant them on the private app in HubSpot. The existing token picks up scope changes; you only need to update Serval if HubSpot rotates the token itself. Neither connect form field is required, and the token is never tested when you save - a blank or mistyped token saves successfully and only fails later at the health check or first workflow run. Run the "Test HubSpot Connection" health check immediately after connecting. Serval attaches your access token only to requests bound for HubSpot's official API host (api.hubspot.com). Custom workflow steps must use standard HubSpot API paths; a request to any other host will not carry the credential and will fail to authenticate. The "Provision HubSpot User with Core Seat" workflow always sends a welcome email and deliberately assigns no role, so HubSpot grants the new user the default core seat with basic contact permissions. To assign a specific role or paid seat, build a custom workflow that sets the role - and note that assigning or unassigning a role with a paid seat requires the billing-write scope on the private app. "Unsubscribe from Marketing Emails" uses HubSpot's legacy email system: it reads every subscription type for the given email address and unsubscribes each active one individually, reporting per-type results (succeeded, already unsubscribed, or failed). It takes an email address rather than a contact record, so it also works for people who exist only in HubSpot's email system. Both installable workflows require installer approval by default. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your HubSpot integration. # incident.io Source: https://docs.serval.com/sections/integrations/incident-io Connect incident.io to Serval with an API key so workflows can read and manage incidents, alerts, escalations, on-call schedules, and everything else in the incident.io API. ## About incident.io incident.io is an incident management and on-call platform. Serval connects to it with a single API key - you paste it in once, Serval verifies it directly with incident.io, stores it securely, and attaches it to every request a workflow makes on your behalf. Serval identifies your incident.io organization automatically from the key, so there is nothing else to fill in. Serval only ever sends the key to one host for this integration: api.incident.io. **Authentication:** incident.io API key - a single key pasted into Serval. There is no OAuth or sign-in flow. **Data sync:** None. There is no background sync, no webhooks or triggers, and no ticket or asset ingestion - all data access happens on demand when a workflow runs, so results are always exactly as fresh as what incident.io returns at that moment. ## What the incident.io integration enables | Capability | Description | | - | - | | Full incident.io API access | Workflows use the "incident.io API request" action to reach all 74 endpoint paths of the incident.io API: incidents (including creating and editing them), alerts, alert routes and sources, escalations and escalation paths, on-call schedules with entries and overrides, follow-ups, incident roles, statuses, types, timestamps, updates, attachments and relationships, custom fields, severities, users, incident.io workflows, catalog data, actions, and IP allowlists. | | Typed, checked requests | The action is generated from incident.io's published API specification, so request paths, parameters, and response shapes are checked while a workflow is being written - mistakes are caught before anything runs. | Anything defined in the [incident.io API](https://api-docs.incident.io/) can be accessed through Serval. ## Get your credentials Serval needs an incident.io API key. Keys in incident.io are created with a specific set of permissions, and Serval can only do what the key allows - so create the key with permissions covering everything your workflows will do. incident.io's API documentation lives at [api-docs.incident.io](https://api-docs.incident.io/). Log in to your [incident.io dashboard](https://app.incident.io/) and click the gear icon (Settings) in the bottom left corner of the screen. Under your current organization section, click **API and Integrations**. Scroll down to the **API and Webhooks** section. Click the **API** tile, then click **Open**. Create (or copy) the API key and store it somewhere safe. incident.io shows the full key only once, at creation time. If you lose it, you will need to create a new key. Pick the key's permissions to match every endpoint your workflows will call. A key that can only do a few things will still connect successfully - the gaps only show up later, when a workflow calls something the key cannot access. ## Connect in Serval In Serval, find **incident.io** in the integrations list and choose to connect it. The form has a single field, **API Key**, shown as a password field with the helper text "Your incident.io API key with appropriate permissions". The label carries no asterisk and the form does no checking of its own, but the key is required - Serval validates it when you submit. Click **Submit**. Serval contacts incident.io to confirm the key works and to identify which incident.io organization it belongs to. If the key is invalid, the save fails with the generic error "Failed to install integration (HTTP 500)" - the underlying reason from incident.io is not shown, so re-check the pasted value and try again. When you later edit the connection, the saved key displays obfuscated - bullet characters with only the last 4 characters visible. Select the pencil icon next to the masked value (or the **Replace** button, if you are reconnecting through the connect dialog) to clear the field, then paste a complete new key and save. On the connection settings form the **Update** button stays disabled until you change something, so an untouched form cannot be resaved by accident. Saving a cleared field without a complete new key fails with an error and leaves the existing credential untouched - every successful save requires a full, valid key. A replacement key must belong to the same incident.io organization. Serval re-identifies the organization from whatever key you save, so a key from a different organization re-points this connection at that organization with no warning. ## Verifying the connection This integration does not ship separate health-check workflows, so the Health Checks panel that appears for some other integrations is absent here. Verification happens at save time instead: every successful save - the first connect or a later key replacement - means Serval reached incident.io with your key, confirmed it is valid, and identified the organization it belongs to. That check confirms validity only, not permissions. Any live key passes it, so a key created with narrow permissions saves cleanly and only reveals its gaps when a workflow calls an endpoint the key cannot access. To exercise the connection beyond save-time validation, run a small workflow that lists incidents (requesting a single result is enough). If the connection saved fine but that call fails, the key is valid but its permissions are too narrow - create a new key with the permissions your workflows need and swap it in. ## Gotchas and troubleshooting Save-time validation only proves the key is valid - any valid key passes it, regardless of permissions. A key created with narrow permissions will save successfully and then fail workflow calls against endpoints it cannot access. Create the key with permissions covering every endpoint your workflows use. Invalid-key errors are generic: a bad or expired key surfaces as this one message with no provider detail, and the underlying reason from incident.io is not shown in the UI. Re-check that you pasted the complete key, then try again. If it still fails, contact support. On edit, the saved key shows only as bullets plus its last 4 characters, and Serval never sends that placeholder back. Every save of this form re-validates whatever key it receives, so saving without entering a full new key fails - the connection settings form shows "Failed to update configuration", and the reconnect dialog shows an error beginning "Failed to update integration". Either way your existing credential is left untouched. To make any change stick, paste the entire new key. Every save re-derives the connected organization from the key itself. Pasting a key from a different incident.io organization re-points the connection at that organization without any warning or guard - double-check which organization a key belongs to before replacing. incident.io returns list data in pages with a continuation cursor. A workflow that needs more than one page must keep requesting, feeding each response's cursor into the next request, until the cursor comes back empty - a single request only ever returns the first page. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your incident.io integration. # Ironclad Source: https://docs.serval.com/sections/integrations/ironclad Connect Serval to Ironclad, a contract lifecycle management platform, to read contract workflows, track approvals and signatures, add comments, and search records on demand. ## About Ironclad Ironclad is a contract lifecycle management (CLM) platform that covers contract creation, negotiation, approvals, signatures, and records. Serval connects to your Ironclad account with an OAuth 2.0 client-credentials app and the email of an Ironclad admin user, then calls Ironclad's public REST API on your behalf. Every request Serval makes is performed as a specific Ironclad user - either the person a workflow run is acting for, or your configured admin as the fallback. Note that in Ironclad, a "workflow" is a *contract* workflow (approvals, signatures) - not a Serval workflow. **Authentication:** OAuth 2.0 client credentials (Client ID + Client Secret from an Ironclad OAuth app), plus an Admin Email used to impersonate a user on each request. **Data sync:** On-demand only - there is no background sync or scheduled ingestion. Serval reads from and writes to Ironclad at the moment a Serval workflow runs. ## What the Ironclad integration enables | Capability | Description | | - | - | | Read contract workflows | Shipped Serval workflows "List All Workflows", "Get Workflow by ID", and "Get Workflow by Title" retrieve Ironclad contract workflows with complete metadata - all of them with pagination, one by its ID or Ironclad ID, or one by its exact title. | | Track approvals and signatures | "Get Workflow Approvals" retrieves all approvals for a specific contract workflow. "Get Workflow Sign Status" retrieves the signature step status for a workflow. | | Comment on contract workflows | "Add Workflow Comment" posts a comment to a contract workflow's activity feed, with support for user mentions. | | Search by counterparty | "Search Workflows by Counterparty" finds every contract workflow associated with a counterparty company name. "Search Records by Counterparty" finds Ironclad records by counterparty name and generates signed copy URLs. | | Call any Ironclad public API endpoint | A generic, typed API request action exposes the full Ironclad Public API: contract workflows (list, launch, retrieve, approvals, approval requests, turn history, signers, participants, revert to review, comments, metadata updates, documents, email threads and attachments), records (create, retrieve, replace, update, delete, attachments, XLSX export, smart import), workflow schemas, and webhooks. It can optionally impersonate a different Ironclad user per request. | Anything defined in the [Ironclad API](https://developer.ironcladapp.com/reference) can be accessed through Serval. ## Get your credentials Serval authenticates with an OAuth 2.0 client application that you create inside Ironclad, using the **Client Credentials** grant. You'll also need the email address of an Ironclad admin user (or an admin-privileged service account) that Serval will make requests on behalf of. Ironclad's official guide is here: [Ironclad client credentials grant](https://developer.ironcladapp.com/reference/client-credentials-grant). In Ironclad, click your user profile dropdown (top right) and select **Company Settings**. Select the **API** tab in the left sidebar. The API tab is only visible if the API add-on is enabled for your Ironclad instance. If you don't see it, contact your Ironclad representative. Click **Create new app**, give it a name (e.g. "Serval Integration"), and click **Create app**. Copy both values immediately. The Client Secret is shown only once - it is not retrievable after the modal closes. Store it somewhere safe before continuing. In the app's settings, under **Grant Types**, select only **Client Credentials** (do not enable Authorization Code). Leave Redirect URIs blank. Add the **Requested Resource Scopes** your automations need (for example `public.workflows.read` and `public.records.read`), then click **Save Changes**. Write down the exact scope list - you'll enter the same scopes in Serval, and they must match what the app grants. Note the email address of the Ironclad admin user that Serval should make requests on behalf of. ## Connect in Serval All five fields are required - the form flags any required field left blank with "This field is required" and won't save until it's filled. If an incomplete configuration reaches Serval's backend anyway, it is rejected with a message that begins "Invalid Ironclad configuration" (for example, "client ID is required", "client secret is required", or "scopes are required"). Your Ironclad domain, entered **without** `https://` or any path: `na1.ironcladapp.com` (US Production), `eu1.ironcladapp.com` (EU Production), `demo.ironcladapp.com` (Demo), or `preview.ironcladapp.com` (Preview). Anything that isn't an Ironclad domain is rejected with "Must be a valid Ironclad API base URL (e.g., na1.ironcladapp.com, eu1.ironcladapp.com)". This domain is also used for OAuth authentication, so it must match the environment where you created the app. The OAuth 2.0 client ID from your Ironclad OAuth application (Company Settings > API > Create new app). The OAuth 2.0 client secret from the same app. It is stored encrypted and is required when you first connect. When editing the connection later, the secret appears obfuscated - leave it unchanged to keep the previously stored secret. The email address of an admin user in Ironclad (e.g. `admin@company.com`). API requests are made on behalf of this user when a workflow run doesn't specify someone else. Invalid input shows "Must be a valid email address". A comma-separated list of OAuth scopes, e.g. `public.workflows.read, public.workflows.write, public.records.read`. At least one scope is required, and the list must match the scopes granted on your Ironclad OAuth app. ## Verifying the connection After saving, Serval runs one health check: **Test Ironclad Connection** - verifies the integration is properly configured and can authenticate. Serval performs the full OAuth client-credentials token exchange with your scopes, then requests a single contract workflow from Ironclad as your configured Admin Email. * On success: "Successfully authenticated with Ironclad" * On failure: "Unable to connect to Ironclad. Please verify your Client ID, Client Secret, and Admin Email are valid." A green test but failing automations usually means a per-user permission gap: the health check runs as your Admin Email, but Serval's shipped Ironclad workflows impersonate the workflow run's target user. If that person isn't a real Ironclad user or lacks permission to see the contract in question, their requests fail even though the connection test passes. ## Gotchas and troubleshooting Throughout the Ironclad API and this integration, a "workflow" is an Ironclad contract workflow (approvals, signatures, turn history) - not a Serval automation workflow. Keep the two concepts separate when naming and reading automations. The scopes you enter in Serval are sent verbatim with every token request. If they don't match what the Ironclad OAuth app actually grants, the token exchange fails ("failed to get OAuth token") and requests are rejected. When you change scopes, update both the Ironclad app and the Serval connection together. Admin Email is required by both the connection form and Serval's backend validation. Every API call is made on behalf of an Ironclad user: shipped workflows pass the run's target-user email, and the Admin Email is the fallback when none is set. Requests are scoped to the impersonated user's Ironclad permissions, so the Admin Email must belong to a real Ironclad user with sufficient access. If neither value is present, the request fails with "admin email or x-as-user-email is required". Only `na1.ironcladapp.com`, `eu1.ironcladapp.com`, `demo.ironcladapp.com`, `preview.ironcladapp.com`, or bare `ironcladapp.com` are accepted - without `https://` or a trailing path. The same domain is used to reach Ironclad's OAuth token endpoint and is enforced by Serval's outbound request allow-list, so an environment mismatch breaks both authentication and API calls. An OAuth app created in one Ironclad environment (NA production, EU production, demo, preview) cannot be used in another. Create a separate OAuth app per environment and a separate Serval connection for each. For teams building custom automations: Serval automatically adds Ironclad's `/public/api/v1` prefix to every request made through the generic API request action, so enter request paths without it. Including the prefix yourself produces a doubled path and a not-found error from Ironclad. A few operations (such as a workflow's signature-step status) are not part of the bundled API specification; they're still reachable through the generic action, just without type checking. On the connection's edit form the secret is shown obfuscated; leaving it unchanged preserves the stored secret while your other field edits are saved over the existing values. And remember Ironclad only shows the secret once at app creation - capture it before closing the modal. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Ironclad integration. # Iru Source: https://docs.serval.com/sections/integrations/iru Iru (formerly Kandji) is a device management (MDM) platform for your Mac fleet - Serval connects to it to run device workflows, automate compliance checks, and sync your Macs into Serval's asset inventory. ## About Iru Iru is a cloud-native device management (MDM) and security platform for deploying, configuring, and protecting Macs and other Apple devices at scale. The Serval Iru integration connects to your Iru tenant using an API token plus your tenant's API domain, and all traffic flows securely through Serval. Once connected, Serval gets typed access to the full Iru v1 API (roughly 80 endpoints), plus prebuilt device-inventory and device-compliance workflow bundles and an ingestion workflow that syncs your Mac computers into Serval's asset inventory. **Authentication:** API token (API Key + API Domain) **Data sync:** On-demand through workflows, plus an installable "Ingest Iru Computers" workflow that performs a full sync of your Mac devices into Serval's asset inventory on each run. ## What the Iru integration enables | Capability | Description | | - | - | | Iru API requests | The "Iru API request" action makes typed calls across the Iru v1 API: devices and device details, device secrets (FileVault key, bypass code, recovery password, unlock PIN), 17 device actions (restart, shut down, lock, erase, lost mode, rename, and more), blueprints and library items, Prism reports, tags, users, threat details, Apple ADE integrations, self-service categories, and settings/licensing. | | Device Inventory workflows | Prebuilt bundle: Get Iru Device Details, Get All Iru Devices (full inventory, automatically fetched across pages), and Get Iru Devices for User (looked up by email). | | Device Compliance workflows | Prebuilt bundle: Find Iru Devices with Failing Updates, Check Iru Devices Not Checked In Today, Check Overdue macOS Updates in Iru, List Iru Devices with Less Than 100 GB Free Space, and Check Device Uptime and Restart if Needed (restarts a user's device, with a notification to the user, when uptime exceeds 10 days - this one requires installer approval by default; the rest run without approval). | | Mac asset ingestion | The "Ingest Iru Computers" workflow syncs every Mac in Iru into Serval's asset inventory, enriching each record with detailed per-device information where available. | | Connection health checks | Three built-in checks exercise different parts of the Iru API, so a token-permission gap shows up as exactly one failing check instead of a vague error. | Anything defined in the [Iru API](https://api-docs.iru.com/) can be accessed through Serval. ## Get your credentials You need two things from Iru: an **API token** and your tenant's **API domain**. The official walkthrough is [Iru's API token guide](https://support.kandji.io/kb/kandji-api). Tenant hostnames and the support article still use the kandji.io domain. Sign in as an Account Owner or Administrator. Roles without Settings access (such as Standard or Help Desk) cannot reach the Access tab unless granted a custom permission set. Go to **Settings**, open the **Access** tab, scroll to the **API token** section, and click **Add API Token**. Name it (for example, "Serval Integration"), optionally add a description, and click **Create**. Copy the token and store it securely, then confirm the "I have copied the token..." checkbox and click **Next**. Iru never displays the cleartext token again after this screen. If you lose it, you'll have to create a new token. In the **Manage API Permissions** dialog, click **Configure** and enable a permission for each capability Serval will use. At minimum (for the health checks and asset sync): **Tag list**, **Device list**, **Device details**, and **Blueprint list**. Add **Device ID** and device-action permissions such as **Restart device** if you plan to install the inventory or compliance workflow bundles. Click **Save**. Iru permissions are granted per endpoint, and you can edit them later via the token's **View > Permissions** tab. A missing permission causes a "permission denied" error on that one call while everything else works. If your Iru dashboard is at acme.kandji.io, your API domain is **acme.api.kandji.io**. EU tenants use **acme.api.eu.kandji.io**. The iru.com equivalents - **acme.api.iru.com** (or **acme.api.eu.iru.com**) - work as well; both hosts serve the same API. The API domain is not the same as your dashboard address. ## Connect in Serval In Serval, open the Iru integration and start a new connection. Enter your tenant's API domain, for example yourcompany.api.kandji.io (or yourcompany.api.eu.kandji.io for EU tenants). The iru.com hosts are accepted too: yourcompany.api.iru.com and yourcompany.api.eu.iru.com. The field validates the format and rejects anything else with: "Must be a valid Iru API domain (e.g., yourcompany.api.kandji.io, yourcompany.api.iru.com, or yourcompany.api.eu.kandji.io)" Paste the full Iru API token into the **API Key** password field. Save, then verify the connection using the health checks below. **When editing an existing connection:** the stored API Key is shown obfuscated, so you must re-paste the full token to update it. Leaving **API Domain** blank on an update keeps the previously saved domain. Serval only ever sends your token to your own Iru API host - addresses ending in .api.kandji.io, .api.eu.kandji.io, .api.iru.com, or .api.eu.iru.com. Any other destination receives no credentials. ## Verifying the connection The integration ships three health checks, each exercising a different part of the Iru API: 1. **Test Iru Connection** - verifies authentication with a lightweight call that lists your tags. Success: "Successfully authenticated with Iru at \[your API domain]". Failure: "Unable to connect to Iru at \[your API domain]." followed by a specific reason - for example, an expired token adds: "The API token is invalid or expired. Please verify your API token in the Iru integration settings." 2. **List Iru Devices** - lists up to 100 devices and counts them. Success: "Successfully listed \[number] devices from Iru". Failure: "Unable to list devices from Iru." plus a specific reason. 3. **List Iru Blueprints** - lists your blueprints and counts them. Success: "Successfully listed \[number] blueprints from Iru". Failure: "Unable to list blueprints from Iru." plus a specific reason. If Iru itself is having a temporary problem, the device and blueprint checks append: "Iru returned a server error. This is likely a temporary issue with Iru's API - please try again later." The connection check words it as: "Iru returned a server error during authentication. This is likely a temporary issue - please try again later." If the connection test passes but the devices or blueprints check fails, your token authenticates fine but is missing one endpoint permission. The failing check tells you exactly which one to add in Iru: a failing device check means the **Device list** permission is missing; a failing blueprint check means **Blueprint list** is missing. ## Gotchas and troubleshooting Iru API tokens carry a per-endpoint permission list. A token missing one permission returns "permission denied" on that single call - Serval surfaces this as: "The Iru API token may not have the required permissions. Please check that the necessary privileges are granted." (The connection check words it slightly differently: "The API token is not authorized to access Iru. Please ensure the token has been granted the necessary permissions in Iru.") Fix it in Iru under the token's **View > Permissions** tab. The asset sync additionally needs **Device details**, and the prebuilt workflow bundles need **Device ID** plus device-action permissions such as **Restart device** (for the uptime-restart workflow). Missing permissions can also surface as a not-found error: "The requested Iru resource was not found. This may indicate missing permissions or incorrect API domain configuration." Verify both the token's endpoint permissions in Iru and the **API Domain** value in Serval before assuming the resource doesn't exist. Enter the API subdomain (acme.api.kandji.io), not your dashboard address (acme.kandji.io). EU tenants use acme.api.eu.kandji.io, and the iru.com equivalents (acme.api.iru.com, acme.api.eu.iru.com) work as well. The form rejects anything else with: "Must be a valid Iru API domain (e.g., yourcompany.api.kandji.io, yourcompany.api.iru.com, or yourcompany.api.eu.kandji.io)" - and Serval only attaches your token to requests bound for valid Iru API hosts, so a wrong domain means no credentials are ever sent. The connection check reports: "The API token is invalid or expired. Please verify your API token in the Iru integration settings." The device and blueprint checks word the same problem as: "The Iru API token may be invalid or expired. Please verify your API token is correct." Iru shows the cleartext token only once at creation, and Serval obfuscates the stored key - so to fix this, create or retrieve a valid token in Iru and re-paste the **full** token when editing the connection. You can leave **API Domain** blank to keep the existing domain. The "Ingest Iru Computers" workflow syncs Mac devices only. Non-Mac Apple devices are not ingested as assets, but they remain fully reachable through the "Iru API request" action and the inventory and compliance workflows. Iru returns list results in pages, with a maximum of 300 records per page. Serval's prebuilt workflows (including Get All Iru Devices and the asset sync) page through automatically; if you build your own workflow, keep requesting pages until one returns fewer records than the limit. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Iru integration. # Ivanti Neurons for ITSM Source: https://docs.serval.com/sections/integrations/ivanti-itsm ## About Ivanti Neurons for ITSM Ivanti Neurons for ITSM is an IT-service-management platform. Connecting it to Serval lets you build workflows that read and write Ivanti business objects (incidents, service requests, changes, problems, tasks, and custom objects) through Ivanti's OData REST API. ## What the Ivanti Neurons for ITSM integration enables | Capability | Description | | - | - | | Automation workflows | Trigger automated processes that query, create, and update Ivanti business objects | | API access | Make authenticated calls to the Ivanti OData/REST API from Serval workflows | This integration connects Serval to the Ivanti API for workflow automation. Bidirectional ticket sync is not part of this integration. *** ## Ivanti configuration (in Ivanti) You authenticate Serval with an Ivanti **API Key** (the **Reference ID** of a REST API Key). The key is tied to the tenant, is static, and does not expire. In the Ivanti Configuration Console, go to **Security Controls** → **API Keys**. If you have never used REST API keys on this tenant, create a group for REST API access first. If a group already exists, skip to the next step. 1. Click **Add API Key**. The **New API Key** page opens. 2. The **Reference ID** field is auto-generated — this value is the API Key you will paste into Serval. 3. (Optional) Restrict the key to specific source IPs by clicking **Add New IP** and entering the address. If you do this, the key only works for requests from those IPs. 4. Save the key. A REST API Key only works for the tenant it was created on — a key from one tenant cannot authorize calls to another. If you later see a "not authorized" error, confirm the key belongs to this tenant (and that the request comes from an allowed IP, if you set IP restrictions). The API Key inherits the permissions of the account/role it is associated with. Make sure that account can read and modify the business objects (incidents, service requests, etc.) your workflows will use. *** ## Serval configuration 1. In Serval navigate to **Integrations → All integrations → Ivanti ITSM → Connect**. 2. Complete the form: | Field | Value | | - | - | | Tenant URL | Your Ivanti tenant host, without `https://` or any path. For `https://company.ivanticloud.com` enter `company.ivanticloud.com`. | | API Key | The **Reference ID** from the REST API Key you created above. | 3. Click **Save**. Serval sends the key on each request as `Authorization: rest_api_key={Reference ID}`; you do not need to format the header yourself. Once connected, Serval can query and update Ivanti business objects according to the permissions of the account behind the API Key. *** ## Troubleshooting * Confirm the API Key (Reference ID) was created on the **same tenant** you entered as the Tenant URL. * If you added IP restrictions to the key, make sure Serval's egress IPs are allowed. * Confirm the key is still **active** in **Security Controls → API Keys**. * Make sure the Tenant URL is a host only — no `https://`, no `/api/...` path, no trailing slash. For example `company.ivanticloud.com`. * The tenant host must be an Ivanti Cloud (`*.ivanticloud.com`) address. The account behind the API Key does not have write permission on that business object. Update the account's role in Ivanti to grant the needed access. # IVM Source: https://docs.serval.com/sections/integrations/ivm Connect Serval to IVM's SmartHub-managed industrial vending and smart locker platform so workflows can read machines, locations, products, inventory, and reports on demand. ## About IVM [IVM](https://www.ivminc.com/) provides industrial vending machines, smart lockers, and automated supply distribution hardware, managed through its [SmartHub platform](https://ivminc.com/ivm-smarthub/). The Serval integration connects to the IVM API (version 21.1) so your workflows can look up machines, locations, products, inventory levels, vend history, and reports. All requests flow through Serval's authenticated proxy - nothing is installed on your IVM tenant. **Authentication:** Your IVM API username and password (OAuth2 password grant against your SmartHub identity server). Serval presents IVM's standard OAuth client to the identity server for you, so those are the only credentials you supply. Serval exchanges them for a short-lived access token and reuses it until shortly before it expires. **Data sync:** On-demand only. There is no background sync and no entity ingestion - workflows call the IVM API at the moment they run. ## What the IVM integration enables | Capability | Description | | - | - | | Full IVM API access | The generic "IVM API request" action exposes the full IVM API v21.1 surface (263 API paths spanning 366 operations), covering machines, machine users, locations, products, planograms, categories, portal users, enhanced lockers, smart screens, webhooks, vend history, restriction groups, and more. | | Machine management | List vending machines, look up a machine by ID, and query machine types, status, authorization, purposes, and planograms. | | Inventory and reporting | Access inventory levels, vend history, failed vends, delinquency reports, and the extensive reporting surface (43 standard report endpoints plus 17 custom report endpoints). | | Locations | List and manage the locations where your machines are deployed. | | Product catalog | Browse products, global products, chained products, categories, planograms, and planogram slots. | | Bundled workflows: Inventory Management | An out-of-the-box bundle of four read-only workflows, all defaulting to no approval required: "List IVM Machines", "Get IVM Machine by ID", "List IVM Locations", and "List IVM Products". | Anything defined in the [IVM API](https://ivminc.com/ivm-smarthub/) can be accessed through Serval. ## Get your credentials IVM does not offer a self-serve developer console for API credentials. IVM support provisions an API user account for your tenant. You need four things before connecting: a username, a password, your tenant's API URL, and your tenant's SmartHub identity server URL. Email **[support@ivminc.com](mailto:support@ivminc.com)** and ask them to provision a username and password authorized for IVM API access. See the [IVM SmartHub platform page](https://ivminc.com/ivm-smarthub/) for more on the platform. Confirm which environment you are connecting to and use the matching pair of URLs. Both must be HTTPS. | Environment | API URL | Identity Server URL | | - | - | - | | Production | `https://ivmapi.com/` | `https://smarthubidentity.ivminc.com` | | Staging | `https://staging.ivmapi.com` | `https://stagingidentity.ivminc.com` | The account must be able to authenticate directly against the identity server with its username and password (the OAuth2 password grant). Make sure the account has permission for the data your workflows need. At minimum it should be able to read machine types, machines, and locations - that is what Serval's connection checks exercise. You do not need an OAuth client ID or client secret. IVM's API documentation publishes a single OAuth client that is the same for every customer, and Serval presents it to the identity server automatically on every token request. It is not a per-customer credential, so there is nothing to request and nothing to enter. SSO-only portal logins (for example, Microsoft Entra ID federation) are not API credentials and will not work. The account must support direct username and password authentication. ## Connect in Serval In Serval, add a new IVM connection to open the credential form. Only the API URL, Identity Server URL, Username, and Password are required - if you leave one of the first three blank, the form flags the field with "This field is required" when you save. Client ID, Client Secret, and Scope are optional and should be left blank. The base URL of your IVM API tenant - the field shows [https://ivmapi.com](https://ivmapi.com) as an example. It must start with https\://. The URL's host becomes the connection's display name in Serval. The base URL of your SmartHub identity server - the field shows [https://smarthubidentity.ivminc.com](https://smarthubidentity.ivminc.com) as an example. It must start with https\://. Enter the base URL only - Serval builds the token endpoint itself. Your IVM API username. After saving, it displays masked, with only the last 4 characters visible. Your IVM API password. This is a password-style field, also masked after saving. Unlike the other fields, a blank password is caught at save time by the server, which reports "Invalid IVM configuration: password is required" (the message is lowercase). Serval fills all three in for you: IVM's standard OAuth client, and the `api1 offline_access` scope IVM requires. Fill them in only if IVM tells you your tenant has a dedicated OAuth client or a different scope - and if you set a Client Secret you must also set a Client ID, or the save is rejected with "client secret requires a client ID". Submit the form. Server-side validation failures appear as a message starting with "Failed to install integration: Invalid IVM configuration" followed by the specific problem - for example, "API URL must start with https\://" or "Identity Server URL must start with https\://" if either URL is not HTTPS. When you later edit the connection, any field left blank (or left showing its masked bullet placeholder) keeps its previously stored value. To rotate just the password, use the edit control next to the Password field, enter the new value, and save - everything else is preserved. ## Verifying the connection Serval runs three health checks against your IVM tenant. Each one goes through the full authentication path, so a passing check confirms both your credentials and your URLs. Saving a change on the connection's settings page automatically re-runs the enabled health checks. * **Validate IVM API Connection** - reads the list of machine types in your tenant. Success shows "Successfully connected to IVM API." Failure shows "Unable to connect to IVM API. Please verify your credentials and API URL are correct." * **List Machines** - lists a small sample of machines. Success shows "Successfully listed machines. Found \[number] machines in IVM." (the wording adjusts to "machine" when there is exactly one). Failure shows "Unable to list machines. Please verify your credentials have the necessary permissions." * **List Locations** - lists a small sample of locations. Success shows "Successfully listed locations. Found \[number] locations in IVM." (singular when there is exactly one). Failure shows "Unable to list locations. Please verify your credentials have the necessary permissions." If all three checks pass but a workflow still fails, the most likely cause is permissions: the health checks only verify read access to machine types, machines, and locations. Ask your IVM administrator to confirm the API account can access the other areas your workflows use, such as reports, products, or vend history. ## Gotchas and troubleshooting Authentication uses the OAuth2 password grant against the SmartHub identity server, which requires direct username and password sign-in. Accounts that only sign in through federated SSO cannot authenticate this way, and fail with `invalid_grant`. If connection checks fail with valid-looking portal credentials, request a dedicated API username and password from [support@ivminc.com](mailto:support@ivminc.com). Serval builds the token endpoint itself from the Identity Server URL (trailing slashes are trimmed automatically). If you paste the full token endpoint URL instead of the base URL, the token path gets appended a second time and every authentication attempt fails. Serval rejects any API URL or Identity Server URL that does not start with https\://. On initial connect the error names the field ("API URL must start with https\://" or "Identity Server URL must start with https\://"); when editing, the same check runs on any new value you provide, and the settings page reports "Failed to update configuration" if it fails. When editing the connection, a blank field (or one left showing its masked bullet placeholder) retains the previously stored value. This applies to every field, including the URLs and the optional Client ID, Client Secret, and Scope. This is convenient for rotating a single credential, but it also means you cannot "clear" a field by emptying it - enter a new value to change it. To go back to the standard scope, type `api1 offline_access` rather than blanking the field. Both the username and the password are stored as secrets. When you reopen the connection's settings, each shows as bullet characters plus its last 4 characters. The password sits behind an edit control (a pencil or "Replace" button) you click before typing a new value; the username appears as a directly editable field pre-filled with the masked value. Either way, saving the masked value untouched leaves the stored credential intact - this is expected. The connection's domain and display name in Serval come from the API URL's host. If you update the API URL, the connection is re-keyed to the new host. A failed health check shows "failed to authenticate with IVM" followed by the identity server's own `error` and, when it provides one, `error_description`. The three you are likely to see mean different things: | Error | Meaning | | - | - | | `invalid_grant` | The IVM API username or password is wrong, or the account cannot use direct password sign-in. The description usually says "Invalid UserName or Password". This is the one to expect from a credential problem. | | `invalid_client` | The OAuth client was rejected. On a connection with Client ID and Client Secret left blank this points at Serval or an IVM-side change, not your credentials - contact [support@serval.com](mailto:support@serval.com). If you set a Client ID override, check it and its secret. | | `invalid_request` | The token request was malformed. As above, this is not a credential problem on a blank-override connection - contact [support@serval.com](mailto:support@serval.com). | Token requests time out after 30 seconds, so a slow or unreachable identity server surfaces as an authentication error too. Serval caches each connection's access token for the lifetime the identity server reports, refreshing it five minutes before expiry. A token issued with no stated lifetime is used once and not cached. Changing anything the token was minted under - username, password, client ID, client secret, or scope - retires the cached token immediately, so a rotation takes effect on the next call rather than when the old token would have expired. Serval's proxy only sends requests to subdomains of ivminc.com (such as smarthubidentity.ivminc.com) and to hosts ending in ivmapi.com. The bare ivminc.com domain with no subdomain is not allowed. If your tenant uses a different domain, requests will be blocked - contact Serval support. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your IVM integration. # Jamf Source: https://docs.serval.com/sections/integrations/jamf Connect Jamf Pro to Serval to query Apple device inventory, manage users and groups, send MDM commands, and ingest your computer fleet into Serval's asset inventory. ## About Jamf Jamf Pro is Apple-focused mobile device management (MDM) for macOS, iOS, iPadOS, and tvOS fleets. Connecting Jamf to Serval lets your team query device inventory, manage users and groups, send MDM commands (lock, erase, OS update), manage departments and sites, and ingest your full computer inventory into Serval's asset system - all through Serval workflows that call the Jamf Pro API and Classic API on your behalf. Serval only ever sends authenticated requests to the exact Jamf domain you configure. **Authentication:** Jamf Pro API client (OAuth 2.0 client credentials). You create an API role and API client in Jamf Pro and give Serval the client ID, client secret, and your Jamf Pro hostname. Serval stores the client ID and an encrypted copy of the secret, exchanges them for short-lived bearer tokens against your own Jamf instance, and refreshes tokens automatically - no browser-based sign-in, no user-level consent, no refresh token. Token lifetime is whatever you configure on the API client in Jamf Pro. **Data sync:** On demand. There is no always-on background sync or webhook from Jamf - workflows call the Jamf APIs when they run (subject to each workflow's approval procedure). For asset inventory, schedule the included **Ingest Jamf Computers** workflow to pull your full computer fleet into Serval. ## What the Jamf integration enables | Capability | Description | | - | - | | Computer management | View, search, and retrieve details for managed computers - look up by user, ID, or serial number; read full inventory sections; retrieve FileVault recovery keys (requires approval); get managed/unmanaged device statistics; and list Automated Device Enrollment (ADE) instances. | | User management | Find users by email, ID, or username; list all users; and create user accounts - both standard (end-user) accounts and Jamf Pro administrator accounts require approval to create. | | Group management | Create and manage static computer, user, and mobile device groups - create groups, add computers to static groups, list static user groups, and delete groups (mutating actions require approval). | | MDM commands | Send MDM commands to managed computers and devices - device lock, erase device, schedule OS update, enable/disable Remote Desktop, Bluetooth settings, unlock/delete user account, inventory update, and more. All MDM command workflows require approval. | | Organization | Create and read departments, create sites, and list all sites for organizing resources in Jamf Pro. Creating departments and sites requires approval. | | Asset inventory ingestion | The **Ingest Jamf Computers** workflow paginates through your entire computer fleet and pulls hardware, OS, storage, security, and user details into Serval's asset inventory. | | Full API access in custom workflows | Custom Serval workflows can call any Jamf Pro API endpoint (JSON) and any Classic API endpoint (JSON or XML) with typed request/response schemas, using the credentials you configured. | Anything defined in the [Jamf Pro API](https://developer.jamf.com/jamf-pro/reference/jamf-pro-api) or the [Jamf Classic API](https://developer.jamf.com/jamf-pro/reference/classic-api) can be accessed through Serval. ## Get your credentials Serval authenticates with a Jamf Pro **API client**: an API role defines the privileges Serval will have, and an API client (assigned that role) provides the client ID and secret you'll paste into Serval. See Jamf's official guide, [API Roles and Clients](https://learn.jamf.com/en-US/bundle/jamf-pro-documentation-current/page/API_Roles_and_Clients.html), for full details. Log in to Jamf Pro and open **Settings**, then search for "API roles and clients" (under **System**). On the **API Roles** tab, click **+ New**. Name the role (e.g. "Serval"), select the privileges you want Serval to have, and click **Save**. You can reuse an existing role instead. You control exactly what Serval can do through this role - grant only the privileges for the capabilities you plan to use, and leave out the rest. You can always add more privileges to the role later without reconnecting in Serval. On the **API Clients** tab, click **+ New**. Name the client (e.g. "Serval Integration"), assign the API role(s) you just created, optionally set a custom access-token lifetime, confirm the client is **Enabled**, and click **Save**. Click **Generate client secret** and copy both the **Client ID** and the **Client Secret** immediately - Jamf shows the secret only once. You'll paste both into Serval. Jamf displays the client secret only at generation time. If you lose it, you'll need to generate a new one - which invalidates the old secret. API roles in Jamf Pro cover both the Pro and Classic APIs. Several Serval workflows and health checks (listing users, computer groups, and departments; creating users and static groups) use the Classic API, so grant the corresponding read/create privileges when building the role. ## Connect in Serval **API Domain** (required) - your Jamf Pro hostname, with no https\:// and no trailing path. Works for both Jamf-hosted (yourcompany.jamfcloud.com) and self-hosted (jamf.yourcompany.com) instances; self-hosted servers listening on a non-standard port can include it (jamf.yourcompany.com:8443). The form requires a hostname with at least one dot, plus an optional :port, and rejects anything else with: "Enter a valid Jamf Pro hostname with an optional port (e.g., yourcompany.jamfcloud.com or jamf.yourcompany.com:8443)". **Client ID** (required) - the API client's client ID from Jamf Pro. Stored and shown back in plaintext on the edit screen. **Client Secret** (required) - the secret you copied when you clicked **Generate client secret** in Jamf Pro. Entered as a password field; after saving, Serval displays it masked (bullets plus the last 4 characters). **Editing the connection later:** API Domain and Client ID come pre-filled with their stored values, and Client Secret is shown masked. Leave the pre-filled Client ID in place - submitting the form with that field cleared overwrites the stored Client ID and breaks the connection until you re-enter it. The masked Client Secret is kept unchanged if you don't touch it. To rotate the secret, click the pencil icon on Client Secret, paste the complete new secret (and update the Client ID too if it changed), then click **Update**. Serval automatically re-runs the health checks after you save changes. ## Verifying the connection Six health checks run against your instance to verify connectivity and privileges, and they re-run automatically whenever you update the connection settings. Each check is an API call that exercises a specific privilege, so all six run regardless of which privileges your API role grants - a check whose privilege you left off the role will simply fail with a permission hint. This is expected if you intentionally scoped the role down, and you can safely ignore failures for capabilities you don't plan to use. * **Test Jamf Connection** - verifies Serval can authenticate with your Jamf Pro instance by performing the token exchange and calling a lightweight endpoint that also reports your Jamf Pro version. * Success: "Successfully authenticated with Jamf Pro at \[domain] (version \[number])" * Failure: "Unable to connect to Jamf Pro at \[domain]." followed by a status-specific hint - invalid credentials (401): "The OAuth client credentials are invalid or expired. Please verify your Client ID and Client Secret in the Jamf integration settings."; not authorized (403): "The OAuth client is not authorized to access Jamf. Please ensure the client has been granted the necessary permissions in Jamf Pro."; server errors (500/502/503): "Jamf returned a server error during authentication. This is likely a temporary issue - please try again later." * **List Jamf Computers** - checks that Serval can list computer inventory records via the Jamf Pro API (first page of 10). * Success: "Successfully listed computers from Jamf Pro (\[number] total)" * Failure: "Unable to list computers from Jamf Pro." followed by a status-specific hint - 401: "The Jamf API credentials may be invalid or expired. Please verify the OAuth client credentials are correct."; 403: "The Jamf OAuth client may not have the required permissions. Please check that the necessary privileges are granted."; 404: "The requested Jamf resource was not found. This may indicate missing permissions or incorrect API domain configuration."; 500/502/503: "Jamf returned a server error. This is likely a temporary issue with Jamf's API - please try again later." * **List Jamf Mobile Devices** - checks that Serval can list mobile device inventory records via the Jamf Pro API (first page of 10). Passes with a count of 0 if you manage no mobile devices. * Success: "Successfully listed mobile devices from Jamf Pro (\[number] total)" * Failure: "Unable to list mobile devices from Jamf Pro." followed by the same status-specific hints as the computers check. * **List Jamf Users** - checks that Serval can list user accounts via the Classic API (there is no Pro API endpoint for listing users), so your API role's privileges must cover Classic API user reads. * Success: "Successfully listed \[number] users from Jamf Pro" * Failure: "Unable to list users from Jamf Pro." followed by the same status-specific hints as the computers check. * **List Jamf Computer Groups** - checks that Serval can list computer groups via the Classic API. * Success: "Successfully listed \[number] computer groups from Jamf Pro" * Failure: "Unable to list computer groups from Jamf Pro." followed by the same status-specific hints as the computers check. * **List Jamf Departments** - checks that Serval can list departments via the Classic API. * Success: "Successfully listed \[number] departments from Jamf Pro" * Failure: "Unable to list departments from Jamf Pro." followed by the same status-specific hints as the computers check. If the connection test passes but the users, computer groups, or departments checks fail with a permission hint, your API role is missing Classic API privileges. Those three checks read users, computer groups, and departments through the Classic API - add the corresponding read privileges to the role in Jamf Pro. ## Gotchas and troubleshooting Every workflow and health check is limited by the privileges on the API role assigned to your API client. A 403 from a health check means the role is missing a privilege. The user, computer group, and department health checks (and several workflows, such as creating users and static groups) use the Jamf Classic API, so grant the corresponding read/create privileges when building the role - API roles in Jamf Pro cover both the Pro and Classic APIs. Enter only the hostname - no https\:// prefix and no path. Self-hosted Jamf Pro servers listening on a non-standard port (commonly 8443) can append it, e.g. jamf.yourcompany.com:8443. The form rejects anything else with: "Enter a valid Jamf Pro hostname with an optional port (e.g., yourcompany.jamfcloud.com or jamf.yourcompany.com:8443)". A newly created API client must be set to **Enabled** in Jamf Pro before saving. A disabled client fails the connection test with an authentication error even when the Client ID and Secret are correct. Jamf displays the client secret only at generation time. Copy it immediately when you click **Generate client secret**. If you lose it, generate a new secret in Jamf Pro and update the integration in Serval - generating a new secret invalidates the old one. On the edit screen, API Domain and Client ID are pre-filled with their stored values and Client Secret is shown masked (bullets plus its last 4 characters). Leave the pre-filled Client ID in place - do not clear the field before submitting, or the stored Client ID will be overwritten and the connection will break until you re-enter it. The masked Client Secret is kept unchanged if you don't touch it, so you only need to re-enter it when rotating credentials: click the pencil icon on Client Secret, paste the complete new secret (and the new Client ID if it changed), then click **Update**. Serval automatically re-runs the health checks after every update, so a credential mistake shows up immediately. Serval will only send authenticated requests to the exact hostname you entered as API Domain - the comparison is case-insensitive and exact, with no wildcard or subdomain matching, and the port must match too (a domain without a port means the standard HTTPS port 443). If your Jamf Pro instance moves to a new hostname or port (e.g. a jamfcloud.com rename or a migration to a custom domain), workflows and health checks will fail until you update the API Domain in the integration settings. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Jamf integration. # Jamf Protect Source: https://docs.serval.com/sections/integrations/jamf-protect Connect Jamf Protect to Serval to triage macOS security alerts, inspect enrolled computers, manage plans and analytics, and read tenant audit logs. ## About Jamf Protect Jamf Protect is Jamf's endpoint-security product for macOS - detection, visibility, and compliance for Mac fleets. Connecting it to Serval lets your team list and triage security alerts, look up enrolled computers, inspect plans and the analytics catalog, read tenant audit logs, and remove computer records - all through Serval workflows that call your tenant's Jamf Protect GraphQL API on your behalf. Serval only ever sends authenticated requests to the exact Protect tenant you configure. **Authentication:** Jamf Protect API client. You create an API client in the Protect console and give Serval the Client ID and Password plus your tenant name. Serval stores the Client ID and an encrypted copy of the password, and exchanges them for short-lived access tokens against your own tenant on demand - no browser-based sign-in and no user-level consent. **Data sync:** On demand. There is no background sync - workflows call the Jamf Protect API when they run (subject to each workflow's approval procedure). ## What the Jamf Protect integration enables | Capability | Description | | - | - | | Alert management | List macOS security alerts filtered by severity range (Informational, Low, Medium, High) and set alert status (New, InProgress, Resolved) for up to 100 alerts at a time (requires approval). | | Computer management | List enrolled computers with inventory details (serial, host name, OS, agent version, plan, connection status), find a computer by serial number, and delete computer records (requires approval). | | Tenant administration | List the analytics catalog (Jamf-managed and custom detections), retrieve a plan with its associated analytics, and read tenant audit logs within a date range (retained one year). | | Full API access in custom workflows | Custom Serval workflows can send any GraphQL query or mutation to your tenant's API with the credentials you configured. | ## Get your credentials Serval authenticates with a Jamf Protect **API client**. See Jamf's guide, [Creating an API Client in Jamf Protect](https://learn.jamf.com/r/en-US/jamf-protect-documentation/Creating_an_API_Client_in_Jamf_Protect), for full details. Note that tenants are limited to five API clients. Log in to Jamf Protect and go to **Administrative** → **API Clients**, then select **Create API Client**. Name the client (e.g. "Serval Integration") and assign a role. A read-only role covers the listing workflows; updating alert status and deleting computers need the matching write permissions. You can change the role later without reconnecting. Copy the **Client ID** and the generated **Password** immediately - the password is shown only once. ## Connect Jamf Protect to Serval In Serval, go to **Settings** → **Integrations** and select **Jamf Protect**. Enter your Protect tenant (the first part of your tenant URL, e.g. `your-tenant` for `https://your-tenant.protect.jamfcloud.com` - pasting the full URL also works), the **Client ID**, and the **Password**. Click connect. Healthchecks run immediately and verify the credentials can reach your tenant's alerts, computers, and analytics. # Jamf Security Cloud Source: https://docs.serval.com/sections/integrations/jamf-security-cloud Connect Jamf Security Cloud to Serval to query device risk states, manage manual risk overrides, and remove devices - across iOS, iPadOS, Android, macOS, and Windows endpoints. ## About Jamf Security Cloud Jamf Security Cloud (the former Wandera RADAR platform) provides mobile threat defense and endpoint risk assessment for iOS, iPadOS, Android, macOS, and Windows devices. Connecting it to Serval lets your team query each enrolled device's current risk state, look devices up by UEM external ID or device GUID, set or clear manual risk-level overrides, and delete devices - all through Serval workflows that call the Jamf Security Cloud Risk and Device Lifecycle APIs on your behalf. Serval only ever sends authenticated requests to `api.wandera.com`. **Authentication:** RADAR application credentials. You create an API application in the Jamf Security Cloud portal and give Serval the Application ID and Application Secret. Serval stores the ID and an encrypted copy of the secret, and exchanges them for short-lived (15-minute) tokens on demand - no browser-based sign-in and no user-level consent. When you connect, Serval validates the credentials and automatically discovers your RADAR customer ID from the login token, so workflows never ask for it. **Data sync:** On demand. There is no background sync - workflows call the Jamf Security Cloud APIs when they run (subject to each workflow's approval procedure). ## What the Jamf Security Cloud integration enables | Capability | Description | | - | - | | Risk monitoring | List the risk states of all enrolled devices (risk level, activity status, UEM enrollment state, device details), or look up a single device by its UEM external ID or Jamf Security Cloud GUID. | | Risk management | Manually override a device's calculated risk level (HIGH, MEDIUM, LOW, or SECURE), or reset an override so the device returns to the risk level calculated by Jamf Security. Both require approval. | | Device lifecycle | Asynchronously delete devices from Jamf Security Cloud by external ID and/or GUID (up to 500 per request). Requires approval. | | Full API access in custom workflows | Custom Serval workflows can call the Risk API (v1 and v2) and Device Lifecycle API endpoints with typed request/response schemas, using the credentials you configured. | Rate limits are enforced by Jamf: 5 requests per second and 10,000 per day per application integration, counted separately for logins and data requests. ## Get your credentials Serval authenticates with a RADAR **API application**: an Application ID and Application Secret pair created in the Jamf Security Cloud portal. Log in to the Jamf Security Cloud (RADAR) portal and go to **Settings**, then **Security Integrations**. Create a new application key for Serval (e.g. named "Serval Integration"). Copy the **Application ID** and **Application Secret** immediately - the secret is shown only once. You'll paste both into Serval. ## Connect Jamf Security Cloud to Serval In Serval, go to **Settings** → **Integrations** and select **Jamf Security Cloud**. Paste the **Application ID** and **Application Secret** from the RADAR portal. Click connect. Serval validates the credentials against Jamf Security Cloud immediately - a failed connect means the credentials were rejected, and the error will say so. On success, Serval discovers and stores your RADAR customer ID automatically. # Jenkins Source: https://docs.serval.com/sections/integrations/jenkins Connect a Jenkins controller to discover inventory and call its core or installed-plugin HTTP APIs from Serval workflows. This beta integration uses Jenkins's [Remote Access API](https://www.jenkins.io/doc/book/using/remote-access-api/). ## Configure Jenkins 1. Create a dedicated Jenkins account. For discovery, grant **Overall/Read** and **Job/Read** on the relevant folders and jobs. Grant additional permissions only for the operations your workflows need; build, configuration, script and administration APIs can change the controller or execute code. See [Jenkins permissions](https://www.jenkins.io/doc/book/security/access-control/permissions/). 2. Generate an API token in that account's **Security** settings. Use the username and token, not an account password. Modern Jenkins [exempts API-token requests from CSRF crumbs](https://www.jenkins.io/doc/book/security/csrf-protection/); leave CSRF protection enabled. 3. Confirm the controller's HTTPS address, including any context path, such as `https://jenkins.example.com/jenkins`. Serval must have a route to this address and trust its TLS certificate. ## Connect to Serval 1. Open **Integrations**, find **Jenkins**, and choose **Connect**. 2. Enter the controller URL, username, and API token. 3. Save and run the authentication, job listing, and agent listing healthchecks. Healthchecks perform reads only. They do not establish permission to build jobs or administer Jenkins. To rotate a token, update the connection settings. Changing the controller or username requires a new token. Private controllers require an appropriate self-hosted worker and network routing. Connections created with the initial inventory-only credential format must save their connection settings again before using private-worker routing. ## API coverage | Action | Coverage | | - | - | | `jenkins.apiRequest` | Compatible inventory API: controller/root jobs, job/folder children and recent builds, individual build metadata, agents, and authentication identity. Returns the response body. | | `jenkins.fullApiRequest` | 58 typed core operations: JSON/XML discovery, jobs/configuration/builds, logs/artifacts, queue, agents, views, labels/users, plugins/update center, controller lifecycle, and privileged scripts. Returns body, status, headers, and encoding. | | `jenkins.request` | General authenticated HTTP access for installed plugins and other version-specific routes. Supports GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, repeated query values, custom noncredential headers, and JSON, XML/text, forms, binary and multipart bodies. | Jenkins APIs vary by version and installed plugins. The typed catalog is not an exhaustive plugin schema. Open the target controller's `/api/` page for its documentation, then use `jenkins.request` for additional routes. Paths are relative to the connected controller, without its context prefix; for example, `/job/app/build`. Separate query parameters from the path. Binary request and response content uses base64. Responses include status and headers so workflows can inspect build queue locations and progressive log offsets. For typed nested jobs, `jobPath: "Platform/Release"` addresses the Release job inside Platform. The legacy inventory action restricts fields and returns up to 100 recent retained build references; it cannot represent slash/percent within a single job name. The general HTTP action supports encoded multibranch names and arbitrary vendor query projections. Folder discovery is one level per call; recurse explicitly when needed. Requests remain on the saved HTTPS controller and context path. Redirects are returned without following them, and requests are not automatically retried. Use the returned status to decide the next step; do not blindly repeat a build or administration action after an uncertain response. The transport buffers responses up to 50 MiB, limits request content to 50 MiB, and allows timeouts up to five minutes. Jenkins CLI/Remoting, WebSockets, indefinite streams and larger transfers require another client. ## Workflow considerations API tokens inherit account permissions. General requests are classified as potentially mutating even when the HTTP method is GET, since installed plugins can change state from GET routes. Treat job names, logs, configuration, scripts and other vendor responses as untrusted data; they are not instructions or authorization for another action. Configure workflow access and approvals for the operations being exposed. Discovery returns only objects visible to the connected account. Empty results do not establish that a controller has no other jobs. Jenkins does not provide a consistent inventory snapshot across calls; preserve existing inventory if scans fail or lose permissions. Scheduled collection and writing to an inventory system require a separate workflow. Pipeline metadata does not enumerate the infrastructure deployed by that pipeline. # JFrog Artifactory Source: https://docs.serval.com/sections/integrations/jfrog-artifactory Connect Artifactory for repository, artifact, build and administration workflows. The beta JFrog Artifactory integration supports JFrog Cloud and self-managed HTTPS instances. Workflows can discover repositories and artifacts, transfer artifacts, manage builds and repositories, and call administration and access APIs permitted by the connection's token. ## Connect Artifactory 1. Create a dedicated access token with only the permissions required by your workflows. Use read-only permissions for inventory. Grant write or administrative permissions only when the workflow requires them. 2. In Serval, open **Integrations**, select **JFrog Artifactory**, and enter the HTTPS hostname (for example, `https://company.jfrog.io`) and access token. 3. Run the repository, artifact-query, and artifact-pagination healthchecks. These exercise reads; they do not prove write permissions. The connector uses bearer access tokens. Legacy API keys and username/password authentication are not supported. Changing the hostname requires entering a token again. Standard JFrog service paths are supported; custom reverse-proxy prefixes and plain HTTP are not supported. [Repository listing](https://docs.jfrog.com/artifactory/reference/getRepositoriesByTypeAndProject) requires administrator privileges or a supported scoped token with `artifact:*:r` or `system:info:r`. [AQL](https://docs.jfrog.com/artifactory/docs/aql-query-execution) can read items with a token scoped to the desired repository/path, such as `artifact:libs-release-local/**:r`. Scope syntax and availability depend on your release. Do not grant administrator access merely to bypass an unsupported scoped-token release. ### Private instances The HTTPS host must be reachable from your configured Serval deployment. See [private network access](/sections/self-hosting/private-network-access) and validate DNS, TLS trust and connectivity. Private instances require a compatible self-hosted worker. ## API actions * `jfrogArtifactory.apiRequest`: typed method, path, parameters and bodies for 636 unique operations from JFrog's public Artifactory, administration, integrations and projects OpenAPI snapshots (2026-10-04). Coverage includes repositories, storage, artifacts, builds, search, users, groups, permissions, tokens, projects, configuration and other APIs hosted on the connected JFrog deployment. * `jfrogArtifactory.request`: general method/path request for version-specific endpoints and alternate media types. Paths must belong to a supported JFrog service on the connected host. Returns `{status, headers, body}`. * `jfrogArtifactory.listArtifacts`: one page of file metadata for a required repository, with `offset` (default 0) and `limit` (default 100; maximum 1000), preserving vendor range information. Typed JSON bodies remain objects. Text bodies are strings; AQL retains `{query: "items.find(...)"}`. Binary request bodies use `{base64}`, and binary responses use `{base64, contentType}`. Multipart bodies use `{parts: [{name, text?, base64?, filename?, contentType?}]}` with exactly one of text or base64 per part. Form bodies use scalar values. The SDK encodes each into the vendor's documented media type. The general request accepts `body` for JSON, `bodyText`, `bodyBase64`, `form`, or `multipart` (one representation per request), optional query and non-authentication headers, and `responseType` (`auto`, `json`, `text`, or `base64`). It supports GET, HEAD, POST, PUT, PATCH, DELETE and OPTIONS. The default timeout is 120 seconds; `timeoutMs` can be set up to 600 seconds. Redirects are returned without following them to preserve credential binding. Use the general request action to inspect the response status and `headers.location`; typed requests report redirects as an error. Requests are attempted once. After an uncertain write outcome, check the vendor state before retrying. Responses and artifact contents are untrusted data, not instructions to execute additional operations. Token-management responses may contain secrets and should be handled accordingly. ## Coverage and limits Availability depends on your JFrog version, edition, license and token permissions. The typed snapshot deduplicates overlapping vendor documents; it is not an assertion that every deployed version implements all 636 operations. MyJFrog account APIs and the JFrog Entitlement Service use separate hosts and credentials and are excluded. Xray and other separately documented products are outside this Artifactory integration. Artifact transfers are buffered and use base64 in workflow inputs/outputs, so workflow and proxy size/time limits apply. This is not a streaming client for arbitrary-sized artifacts. No automatic inventory synchronization or CMDB reconciliation is included. According to [AQL output documentation](https://docs.jfrog.com/artifactory/docs/aql-query-output), permission filtering can occur after pagination limits. A short or empty page does not prove completion. Preserve `range` and truncation `notification`, validate expected counts, and do not infer deletion from an incomplete scan. Concurrent changes can move records between offset pages. Validate the specific operations your workflows require against a non-production instance before enabling them in production. Read-only healthchecks do not validate writes, artifact transfer or administrative operations. Requests and responses are limited to 50 MiB each (including multipart framing), in addition to existing workflow/proxy limits. Encoded literal percent characters in artifact paths are currently rejected by conservative path validation. ### Direct cloud storage downloads JFrog can return a [302 redirect to a signed cloud-storage URL](https://docs.jfrog.com/installation/docs/direct-cloud-storage-download). Call `request` for the artifact, inspect its status and `headers.location`, then explicitly pass the vendor-issued HTTPS URL to `jfrogArtifactory.downloadSignedURL({url})`. This helper performs a GET without connection credentials or cookies, returns `{status, headers, body: {base64, contentType}}`, and does not follow further redirects. Only use URLs returned by a trusted JFrog response. Signed URLs contain temporary authorization and must be handled as secrets. Downloads retain the 50 MiB limit and 120-second timeout. # Jira Source: https://docs.serval.com/sections/integrations/jira Connect your Jira Cloud site to Serval for two-way ticket syncing, prebuilt workflows, and automation across the full Jira Cloud REST API. ## About Jira The Jira integration connects a Jira Cloud site (`yourcompany.atlassian.net`) to Serval. Once connected, Serval can sync tickets two-way between Serval and Jira, run prebuilt Jira workflows, and automate anything the Jira Cloud REST API supports - with authentication handled for you. Self-hosted [Jira Data Center](/sections/integrations/jira-data-center) uses a separate integration and is not covered on this page. **Authentication:** Atlassian OAuth 2.0 (3LO) - either Serval-managed sign-in (recommended) or your own Atlassian OAuth app. Both paths use the same permission picker, so you choose exactly which Jira scopes the connection requests. Installing the Serval Forge app into your Jira site afterward unlocks ticket syncing and service-account features on connections made with either method. **Data sync:** Two-way ticket syncing runs in the background once the Forge app is installed and sync settings are configured; workflow actions run on demand. Access tokens are refreshed automatically for both connection methods. ## What the Jira integration enables | Capability | Description | | - | - | | Two-way ticket syncing | Sync tickets between Serval and Jira, configured in Serval with project, request type or issue type, priority mapping, status mapping, and sync strategy. Works with either connection method: **Sign in with Jira** connections must have the Serval Forge app installed, while your-own-OAuth-app connections can sync without it (installing Forge is recommended so tickets and comments are attributed to their real creators). | | Workflow automation (full Jira Cloud REST API v3) | Serval workflows can call any Jira Cloud REST v3 capability through the proxied Jira API request action, limited to the permissions you granted at connect time, with authentication injected automatically. Service-account and per-user impersonation modes are available per request once the Serval Forge app is installed. | | Prebuilt workflow: Read Jira Issue Details | Retrieves comprehensive details about a Jira issue by its issue key (e.g., PROJ-123) or issue ID - summary, description, status, assignee, reporter, priority, and other fields. Default approval: installer-approval. | | Prebuilt workflow: Create Jira Issue | Creates a new Jira issue in a specified project with customizable fields including summary, description, issue type, priority, and assignee. Default approval: installer-approval. | | Prebuilt workflow: Transition Jira Issue | Moves a Jira issue to a different status (To-Do, In Progress, Done, etc.) - first retrieves the available transitions, then performs the transition. Default approval: installer-approval. | | Prebuilt workflow: List Jira Projects | Lists all Jira projects the user has access to, including name, key, type, and lead information. Default approval: installer-approval. | | Jira Service Management catalog-item ingestion | Imports JSM catalog items (request types) as runnable external workflows, including their request form fields, so employees can order them through Serval and each request maps to a workflow run for centralized approvals and audit history. Ships paused by default and activates only when explicitly enabled. | | Permission presets at connect time | Three curated presets, all checked by default - **Issue Tracking** (read, create, and update issues, and look up users), **Service Management** (JSM requests, customers, and organizations), and **Projects & Administration** (projects, Jira configuration, and webhooks). Expand any preset to toggle individual scopes off, so a connection requests only what your workflows need. | Anything defined in the [Jira Cloud REST API v3](https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/) can be accessed through Serval. ## Get your credentials There are two ways to connect, and only one of them requires Atlassian-side setup. No credentials to create. Serval uses its own registered Atlassian app - you only need a Jira account with access to the site you want to connect, and you'll approve the permissions on Atlassian's consent screen. Skip ahead to **Connect in Serval**. Create an OAuth 2.0 (3LO) integration owned by your Atlassian workspace in the [Atlassian developer console](https://developer.atlassian.com/console/myapps/). If the Sign in with Jira flow runs into OAuth or consent trouble, connecting with your own app is a dependable way to establish the connection. Your-own-app connections support ticket syncing too - installing the Serval Forge app is recommended so tickets and comments are attributed to their real creators. The Serval Forge app attaches to your-own-OAuth-app connections as well as Serval-managed ones. On a your-own-app connection it is **recommended** but not required - ticket syncing works without it, and installing it improves ticket and comment attribution and unlocks service-account and per-user impersonation. Connections made with **Sign in with Jira** still require the Forge app before ticket sync can be configured. In the Atlassian developer console, create a new OAuth 2.0 (3LO) integration, or open an existing one. Under **Permissions**, add the **Jira API** and the **Jira Service Management API** and grant every scope you plan to select in Serval's setup dialog. If a scope you pick in Serval isn't granted here, Atlassian will reject the authorization. The full set Serval can request is: `read:jira-user`, `read:jira-work`, `write:jira-work`, `manage:jira-project`, `manage:jira-configuration`, `manage:jira-webhook`, `read:servicedesk-request`, `write:servicedesk-request`, `manage:servicedesk-customer`, and `offline_access` (always requested so Atlassian issues a refresh token). Granting the full set on the Atlassian app keeps every picker selection available; the connection only receives the scopes you actually select in Serval. Under **Authorization**, paste the **Callback URL** shown in Serval's custom-app setup form into Atlassian's Callback URL field. The callback URL must match exactly - Atlassian rejects any mismatch. Use the Copy button in the Serval form rather than retyping it. From the integration's **Settings** page, copy the **Client ID** and the **Secret** (click **Show** next to the secret). You'll paste both into Serval, along with your Jira site subdomain and an optional display name. ## Connect in Serval This option is badged **Recommended** in the connect modal: "Connect using the Serval-managed Jira integration." Fill in the **Jira site** field (required) with your subdomain only - the `.atlassian.net` suffix is fixed next to the input. Helper text: "For example, if your Jira URL is acme.atlassian.net, enter acme." Leaving it empty shows "Jira subdomain is required"; anything other than letters, numbers, and hyphens - or a value that starts or ends with a hyphen - shows "Please enter a valid subdomain (letters, numbers, and hyphens only)". Under **Permission Presets**, all three presets - **Issue Tracking**, **Service Management**, and **Projects & Administration** - are checked by default. Uncheck a preset to drop its scopes, or expand it to toggle individual scopes off (a partially selected preset shows a mixed checkbox and a "\[n] of \[m]" count). The footer shows "\[number] Jira permission(s) will be requested." At least one permission is required - the Connect button stays disabled until you select one, and submitting without one shows "Select at least one permission." Serval opens Atlassian's authorization screen. Sign in and approve the requested permissions, making sure to select the site that matches the subdomain you entered. (If something unexpected goes wrong before the Atlassian screen opens, the modal shows a generic "Failed to initiate Jira OAuth" message.) Serval binds the connection to your site automatically. On reconnect, the Jira site field is pre-filled from your existing install and the picker pre-checks the permissions currently granted, so you only need to add what's missing. Modal copy: "Connect with an OAuth 2.0 (3LO) integration owned by your Atlassian workspace." * **Display name** (optional) - a friendly label shown in Serval; placeholder "My Company Jira". Helper: "A friendly name shown in Serval - you choose this." * **Jira site** (required) - subdomain only, with the fixed `.atlassian.net` suffix; validated the same way as in the Serval-managed flow. * **Client ID** (required) - from your integration's Settings page; placeholder "00000000-0000-0000-0000-000000000000". Helper: "Found on the Settings page of your OAuth 2.0 (3LO) integration." * **Secret** (required) - password field, placeholder "ATOA...". Helper: "Click Show next to the secret on your integration's Settings page to reveal it." * **Callback URL** - read-only with a Copy button; this is the value you registered in Atlassian. The submit button stays disabled until all required fields are filled and at least one permission is selected. If an invalid value reaches the backend you'll see "clientId is required", "clientSecret is required", "subdomain is required", or "at least one scope is required", surfaced with the prefix "Failed to initiate custom Jira app". Same picker as the standard path: all three presets checked by default, each expandable to toggle individual scopes. Every permission you select here must also be granted on your Atlassian app under Permissions, or Atlassian will reject the authorization. Serval opens Atlassian's authorization screen using your app. Approve the permissions and select the correct site. Complete the Atlassian approval within **10 minutes** of starting. After that, the connection attempt expires and returns "Invalid or expired OAuth state" - just start again from the form. Reconnecting a bring-your-own install opens directly in this form with **Display name**, **Client ID**, **Jira site**, and the granted permissions pre-filled. The **Secret** is never pre-filled and must be re-entered every time - leaving it blank does not keep the existing secret. ### Install the Serval Forge app (required for ticket syncing) Order matters: connect with **Sign in with Jira** first, then install the Forge app. The Forge app upgrades your existing Serval-managed OAuth connection with service-account capabilities - it is not a standalone way to connect, but ticket syncing won't work without it. Connections made with your own Atlassian OAuth app are not upgraded by the Forge app; reconnect with Sign in with Jira if you need ticket syncing. In Serval, open the Jira app and turn on **Ticket Syncing**. Install the regional Forge app for your Serval deployment. EU customers on `app.eu1.serval.com` must use the EU app — the US app sends lifecycle webhooks to the US shard only. Open the [US Serval Forge app install page](https://developer.atlassian.com/console/install/c07d3f13-9bca-4772-8bd1-78cb643ba05c?signature=AYABeH3H0ZqUsljeX7xf7cjSBpYAAAADAAdhd3Mta21zAEthcm46YXdzOmttczp1cy13ZXN0LTI6NzA5NTg3ODM1MjQzOmtleS83MDVlZDY3MC1mNTdjLTQxYjUtOWY5Yi1lM2YyZGNjMTQ2ZTcAuAECAQB4IOp8r3eKNYw8z2v%2FEq3%2FfvrZguoGsXpNSaDveR%2FF%2Fo0Buwn9CCqeYgh1%2BEAlr0oGvQAAAH4wfAYJKoZIhvcNAQcGoG8wbQIBADBoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDGve5jSoRhxnllo%2BiAIBEIA7MzrFlFGrb4Iy5UUirNrX5QJAtKfMDfWNjJ612r2U1%2BTum8UZFPOOU271doEn%2FKZVo911dkk1scv7zhoAB2F3cy1rbXMAS2Fybjphd3M6a21zOmV1LXdlc3QtMTo3MDk1ODc4MzUyNDM6a2V5LzQ2MzBjZTZiLTAwYzMtNGRlMi04NzdiLTYyN2UyMDYwZTVjYwC4AQICAHijmwVTMt6Oj3F%2B0%2B0cVrojrS8yZ9ktpdfDxqPMSIkvHAEKW%2FLX8KhHQrCfkDuzAgjBAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM52N1SKngCx8hQb%2BzAgEQgDtE%2FmCnfl%2Bz7WbS%2BEkpToi%2F2cFLschi1flQ9Ydmfm7ObPDfBCVxU92e9X8klbTIf5eTKCKUZMOobOLN%2BQAHYXdzLWttcwBLYXJuOmF3czprbXM6dXMtZWFzdC0xOjcwOTU4NzgzNTI0MzprZXkvNmMxMjBiYTAtNGNkNS00OTg1LWI4MmUtNDBhMDQ5NTJjYzU3ALgBAgIAeLKa7Dfn9BgbXaQmJGrkKztjV4vrreTkqr7wGwhqIYs5AacHR7PU7QXKh6Sf2GrPIs8AAAB%2BMHwGCSqGSIb3DQEHBqBvMG0CAQAwaAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAwKMa2VNbko%2FI1kEDMCARCAO9x0vKkBou9b%2BSe4TA%2BPKefH9LSKCelNe2fiYRCaK%2FxDqDItkM9WnCRrnkVKyj8FpJXCs8%2BFpPtvZqdHAgAAAAAMAAAQAAAAAAAAAAAAAAAAALDiZ0DneS2rJV8Ssux8NWv%2F%2F%2F%2F%2FAAAAAQAAAAAAAAAAAAAAAQAAADImSOiACTGK7hIfRop51WUYOsukJB3tlCRlXI4Gvvc2TNQdrdvtYoIiMtFb9105M6i9ksQL4DOzGoC%2BQFImYkSpwjo%3D\&product=jira) and install it into the same Jira site you connected. From the Jira ticket-syncing setup in Serval (`app.eu1.serval.com`), follow the **Atlassian app installation page** link. That link targets the EU Forge app, which sends install and token-refresh webhooks to the EU1 backend. The install can take up to five minutes to reflect in Serval. Refresh the Serval page to see the updated status. Installing once upgrades every Sign in with Jira connection to that Jira site across your Serval teams. Select the Jira projects this integration can sync with. Project Management projects appear where PM project syncing is enabled. The project pickers label Service Management projects **JSM** and Project Management projects **PM**. In **Project Routing**, choose a default **Jira project**. For a JSM project, select its **Request type**. For a PM project, select its **Issue type**. Configure the **Required fields** for that destination using the existing default values and optional AI inference. Serval identifies the project kind from Jira. Changing the project or type reloads its field requirements. Subtask creation isn't supported. To route some tickets elsewhere, select a **Routing workflow**, or use **Build a routing workflow in Catalyst** to describe your conditions. The workflow can choose another configured project and its request type or issue type, with any required field values. Serval creates and links the issue; the workflow doesn't need to call Jira's creation APIs. Choose **Use default only** when you don't need conditional routing. Configure status and priority mappings for each selected project, then choose the sync strategy. Selected projects are used for incoming sync when enabled and are the allowed destinations for routing. Updates to an already linked issue continue to use that issue's destination. ## How ticket sync behaves **The sync direction applies to new tickets only.** * **Sync Out**: tickets created in Serval are sent to Jira. Jira issues aren't imported. * **Sync In**: Jira issues are imported into Serval. Tickets created in Serval aren't automatically sent to Jira. * **Two-way Sync**: tickets created in Serval are sent to Jira, and Jira issues are imported into Serval. Updates to synced tickets sync both ways under every direction: changes made in Serval appear on the Jira issue, and changes made in Jira appear on the Serval ticket (comments and attributes, per the Sync Scope toggles). For a one-time import of Jira history with no live connection, use the team's CSV ticket import page instead of ticket syncing. **Assignees.** When an AI-owned Jira issue — for example, a catalog-workflow request Serval created — escalates and syncs out, Serval assigns the issue to its own app account by default. On Jira sources that sync out on escalation, turn on **Leave AI-owned tickets unassigned** to leave those issues unassigned in Jira instead. Human assignments still sync out as normal, and enabling the setting never strips an assignee a person picked up in Jira. **Change activity.** When assignment, status, priority, or title changes sync from Jira Cloud, each activity names the person who made that change if Jira's recent history matches the synced value and identifies an existing user on the Serval team. Otherwise, it keeps the default Serval attribution. Description changes keep the default attribution. A status attributed to a person is also treated as manually chosen by AI status inference. Older activity isn't retroactively attributed to a person. **Attachments.** A file synced from Jira lands on the same Serval message as the comment it was attached to. A file added to an internal Jira comment therefore stays an internal note in Serval rather than surfacing as a public timeline message, so it isn't echoed onto customer-visible or cross-channel threads. **AI replies.** With **AI Auto-Response** on, a customer-visible Jira comment starts an AI reply on an AI-active Serval ticket, as long as Serval can match its author to a user (the Jira account has an email address). Internal comments never do. A comment from someone other than the requester pauses the agent on that ticket; it can be brought back from the ticket in Serval. ### Mirror your Jira workflow as a Request state machine In the Jira ticket-source setup, the **Request State Machine** step can import your synced project's Jira workflow (its statuses and transitions) into Serval's native [status transition rules](/sections/documentation/ticketing/ticket-configuration/statuses#transition-rules) for the Request ticket type. Map every Jira status first, then turn on **Enforce status transitions** to build the state machine from Jira. Once enforced, Requests move only between connected statuses, for both people and Serval AI, matching your Jira workflow. Use **Rebuild from Jira** to re-import after the Jira workflow changes, and edit the result anytime under **Settings → Ticket types** for the Request type. Turning enforcement off lets Requests move between any statuses again. ## Verifying the connection Serval runs three health checks against the connection: **Test Jira Connection** - validates basic connectivity and authentication by looking up the connected user. * Success: "Successfully authenticated with Jira as \[name]" (shows "user" when no display name is available) * Failure: "Unable to authenticate with Jira. Please verify your API credentials and permissions are correct." **List Jira Projects** - validates that the credentials can list projects. * Success: "Successfully listed projects from Jira (sample size: \[number])" * Failure: "Unable to list projects from Jira. Please verify your API credentials have permission to browse projects." **Search Jira Issues** - validates that the credentials can search issues, using a query for issues assigned to the connected user. * Success: "Successfully searched issues in Jira (found: \[number])" * Failure: "Unable to search issues in Jira. Please verify your API credentials have permission to search and read issues." All three checks can pass while ticket syncing still does nothing - they only exercise the OAuth credentials. If sync isn't working, verify the connection was made with Sign in with Jira, verify the Serval Forge app is installed in the Jira site, and allow up to five minutes after installing it. ## Gotchas and troubleshooting The connect modal offers exactly two methods: **Sign in with Jira (OAuth)** (Serval-managed, badged Recommended) and **Use your own Atlassian OAuth app**. The Serval Forge app install is a third step that upgrades an existing Sign in with Jira connection - it is required for ticket syncing and service-account features, it is not itself a way to connect, and it does not attach to bring-your-own app connections. (A legacy Jira Connect app path still exists for older installs only; it is deprecated and not offered to new connections.) After OAuth consent, Serval looks up the subdomain you entered among the sites your Atlassian account authorized. If it isn't there, the connection fails with: "target Jira site '\[subdomain].atlassian.net' not found in accessible resources. Please ensure you have access to this site and selected it during authorization". If no subdomain was given and your account has multiple sites: "multiple Jira sites found (\[number]). Please specify which site to connect by providing the subdomain". On reconnect, the modal jumps straight to the custom-app form and pre-fills Display name, Client ID, and Jira site - but the Secret is never pre-filled and there is no keep-existing-on-blank behavior. It is required client-side, and the backend rejects an empty value with "clientSecret is required". Have the secret handy (or generate a new one in the Atlassian console) before reconnecting. The Forge app's credentials are delivered on install and then re-delivered every five minutes, so it may take up to 5 minutes for the installation to take effect. After installing, refresh the Serval page to see the updated status. Serval requests offline access during authorization specifically so Atlassian returns a refresh token (access tokens expire after about an hour), and refreshes tokens automatically when fewer than 5 minutes of validity remain. If a stored connection somehow lacks a refresh token, calls start failing once the access token expires, with "custom Jira OAuth app access token expired and no refresh token available; reconnect required" - the fix is to reconnect. Also note the connect form's authorization window is 10 minutes; after that you'll see "Invalid or expired OAuth state". Even with the Forge app installed, Jira calls run as the user who connected the integration unless a workflow opts in: on a Sign in with Jira connection upgraded by the Forge app, sending the `X-Use-Connect-Auth: true` header switches to the Forge service account, and `X-As-Jira-User` additionally impersonates a specific Jira account. The opt-in header is harmless on connections without the Forge app, including bring-your-own app connections. Permissions are baked into the OAuth consent and stored on the connection - Atlassian issues tokens only for the scopes granted when the connection was made. To add permissions (for example, enabling **Projects & Administration** after the fact), reconnect the integration - the picker pre-checks what's already granted so you only add what's missing. On a bring-your-own app, also make sure the new scope is granted on the Atlassian app under Permissions first. A workflow that calls an endpoint outside the granted scopes fails with a 401/403 from Atlassian until you reconnect with the scope selected. Two sync-configuration reads are gated by Atlassian behind the `manage:jira-configuration` scope: per-project priority schemes (the priority-mapping picker falls back to the site-wide priority list without it, which can offer options a project's scheme rejects on sync) and the project workflow graph (the **Request State Machine**'s import fails without it). These reads always run with the connection's own token - they do not use the Forge app's service account - so installing the Forge app does not stand in for the scope. When the connection's granted scopes lack `manage:jira-configuration`, the Priority Mapping step shows a warning and the Request State Machine step blocks building or rebuilding (turning an existing state machine off stays possible); reconnect with the **Projects & Administration** preset selected to clear it. The full OAuth scope set for bring-your-own apps is the 10 scopes shown under **Get your credentials** (9 Jira/JSM scopes plus `offline_access`). Serval requests the subset you select in the picker, but granting the full set on the Atlassian app keeps every selection available. The scopes `read:form:jira` and `read:form.field:jira` belong only to the Serval Forge app - do not add them to your OAuth app expecting them to be requested. Self-hosted Jira Data Center uses the separate [Jira Data Center](/sections/integrations/jira-data-center) integration and is not covered by this page. *** Need help? Contact [**support@serval.com**](mailto:support@serval.com) for assistance with your Jira integration. # Jira Data Center Source: https://docs.serval.com/sections/integrations/jira-data-center Connect Serval to your self-hosted Jira Data Center instance with an API token for two-way Jira Service Management ticket sync and on-demand API access. ## About Jira Data Center The Jira Data Center integration connects Serval to a Jira instance you host yourself. It's a separate integration from [Jira (Cloud)](/sections/integrations/jira): it talks directly to your own host and authenticates with an API token you provide instead of OAuth. Once connected, Serval can sync tickets two-way with Jira Service Management projects, and workflows and Catalyst can call your instance's API on demand. The integration is marked **Beta** in the connect UI. If your Jira lives at yourcompany.atlassian.net, use the [Jira (Cloud) integration](/sections/integrations/jira) instead. **Authentication:** API token. You supply your instance's Base URL and a personal access token; Serval stores the token securely server-side and attaches it to every request on your behalf, so workflows never see the raw token. Basic auth (username plus password) isn't supported. Ticket sync on Data Center doesn't use the Serval Forge app. **Data sync:** Two-way ticket syncing with Jira Service Management projects runs in the background once sync settings are configured (Serval polls your instance; inbound webhooks aren't used). Workflow actions run on demand. ## Attribution and service account Jira Data Center personal access tokens can't act as another Jira user. Jira records the token owner as the actor for every write, transition, assignment, and comment. For ticket syncing, create a dedicated Jira service account with the display name **Serval** and generate the token from that account. Don't connect an employee's personal token, because Jira would present that employee as the actor for every change Serval syncs. Grant the service account Jira Service Management agent access and the **Modify Reporter** project permission. It also needs permission to browse the project, create and update requests, add comments, transition issues, and assign issues. For tickets created in Serval, Serval matches the creator's email to a Jira username and sends `raiseOnBehalfOf` to set the request reporter. Jira still records the Serval service account as the actor. For human comments, Serval adds the person's name and email to the comment body. Jira shows the service account on the comment. Serval-generated comments use the **Serval** service-account identity. ## What the Jira Data Center integration enables | Capability | Description | | - | - | | Two-way ticket syncing | Sync tickets between Serval and Jira Service Management projects, configured in Serval with project, request type, priority mapping, status mapping, and sync strategy. Uses the API token you connected—no Forge app install. | | Typed API requests | A "Jira Data Center API request" action covering 283 endpoints, spanning the Jira platform REST API (version 2) and the Jira Agile API - issues, projects, users, workflows, permissions, agile boards, sprints, backlog, epics, and more. Workflows and Catalyst can do anything the connected token is permitted to do. | | Catalyst workflow authoring | Serval's AI knows the Jira Data Center API, so Catalyst can discover the right endpoints and build working Data Center workflows for you. | | Connection health check | Verifies your stored Base URL and token by looking up the account the token belongs to, and reports who the integration is connected as. | Anything defined in the [Jira Data Center API](https://docs.atlassian.com/software/jira/docs/api/REST/latest/) can be accessed through Serval. ## Get your credentials Create the token while signed in as the dedicated Serval service account. There are two ways to get a token, depending on how your instance is set up. On Jira 8.14 and later, use a built-in Jira personal access token. Atlassian's guide is [Using Personal Access Tokens](https://confluence.atlassian.com/enterprise/using-personal-access-tokens-1026032365.html). In Jira, select your avatar at the top right of the screen, then select **Profile**. Select **Personal access tokens** in the left-hand menu. Select **Create token** and give it a name. You can optionally set an expiry - if you do, plan to rotate the token in Serval before it expires. Copy the token immediately - Jira shows it only once. Atlassian also documents personal access tokens in more depth in its [developer guide](https://developer.atlassian.com/server/jira/platform/personal-access-token/). If your instance uses the Resolution "API Token Authentication" Marketplace app instead of native tokens: Click your profile icon and open the **API Token Authentication** link. Create a token on the **My API Tokens** tab. See the [Resolution user guide](https://wiki.resolution.de/doc/api-token-authentication/latest/user-guide) for details. Tokens from the Resolution app work with Serval only from app version **1.7.0** onward. Older app versions require basic authentication, which this integration does not support. ## Connect in Serval In Serval, open your team's integrations page and select **Jira Data Center**. The integration is marked **Beta**. Enter your instance's address, for example [https://jira.example.com](https://jira.example.com). The helper text reads: *The base URL of your self-hosted Jira Data Center instance (e.g. [https://jira.acme.com](https://jira.acme.com)).* Enter the host. Serval removes the https\:// prefix and a trailing slash, and keeps a port (entering [https://jira.example.com:8443/](https://jira.example.com:8443/) stores jira.example.com:8443). Submitting the field empty is rejected with "Base URL is required", and a value Serval cannot read as a host is rejected with "Base URL must be a valid Jira host, e.g. [https://jira.example.com](https://jira.example.com)". A value with a path after the host is rejected too, because Serval stores only the host: see [Context-path deployments](#context-path-deployments-are-not-supported). Paste the token you created into the password field. The helper text directs you to create it from a dedicated Jira service account named Serval and explains that Jira attributes synced changes to that account. Native Jira personal access tokens are the first-party path on Jira 8.14 and later. Resolution app users can generate a token from the app's token page. Serval rejects an empty value and displays **API Token is required**. Submit the form. Serval saves the connection and automatically runs the connection health check. When editing an existing connection, the Base URL field comes pre-filled with the stored host, and the API Token field shows a masked placeholder (bullet characters plus the last 4 characters of the stored token) behind a replace control. Leaving the token untouched or blank keeps the stored token, and leaving Base URL blank keeps the stored host - you only need to fill in the field you are rotating. ## Configure ticket syncing Ticket syncing on Jira Data Center is **Beta**. It is available to every team with the integration connected, and the **Ticket Syncing** tab is marked Beta in the app. Ticket syncing is for Jira Service Management (JSM) service-desk projects. After the connection health check passes, open the Jira Data Center app in Serval and turn on **Ticket Syncing**. Then select the project, select the request type, set the priority mapping, set the status mapping, and choose the sync strategy. Serval polls your instance for new and updated issues. Data Center ticket sync doesn't use inbound webhooks or the Serval Forge app. The connected service account needs the permissions listed in [Attribution and service account](#attribution-and-service-account), including **Modify Reporter** for reporter mapping. Priority mapping offers only the priorities in the selected project's priority scheme, because Jira rejects any other priority when Serval writes an issue. Reading a project's priority scheme is an administrator-level API on Data Center, so if the connected service account can't read it, the priority mapping section shows an error and can't be edited until the account is granted that access. Existing mappings keep syncing in the meantime. ## Verifying the connection The integration has one health check, **Validate Jira Data Center API Connection**. It runs automatically when you connect and again when you save credential changes, and you can re-run it any time from the integration's settings page. It confirms that Serval can reach your instance at the stored Base URL and sign in with the stored token by looking up the account the token belongs to. * On success: "Successfully connected to Jira Data Center as \[name]." - \[name] is the account's display name, or its username if no display name is set. If your instance returns neither, it shows "Successfully connected to Jira Data Center." instead. * On failure: "Unable to connect to Jira Data Center. Please verify your base URL and API token are correct." If the health check passes but a workflow step fails, the token is usually the issue, not the connection. The health check only verifies sign-in - it does not check Jira permissions. Make sure the account the token belongs to has permission in Jira for the projects and actions your workflow touches. ## Gotchas and troubleshooting This integration is for self-hosted Jira Data Center. If your Jira lives at yourcompany.atlassian.net, use the [Jira (Cloud) integration](/sections/integrations/jira) instead. The two aren't interchangeable. Serval always connects to your configured host over HTTPS, so the instance must serve TLS - one that only speaks plain HTTP will not work. Serval also blocks requests to hosts that resolve to internal or private IP addresses, so an instance reachable only on a private network cannot be connected and the health check will fail even with a valid token. Expose the instance on a publicly resolvable HTTPS address and allow inbound access from Serval before connecting. Serval stores only the host portion of your Base URL, so Jira must be served at the root of its host. If you enter a Base URL with a path after the host (for example, [https://apps.example.com/jira](https://apps.example.com/jira)), Serval rejects it rather than saving a connection whose requests would go to the wrong address. Ports are fine: [https://jira.example.com:8443](https://jira.example.com:8443) is stored as jira.example.com:8443. Serval sends the token as a Bearer authorization header. Native Jira personal access tokens (Jira 8.14 and later) support this out of the box. Tokens from the Resolution "API Token Authentication" app accept it only from app version 1.7.0 onward - older app versions require basic authentication, which this integration does not support. This version provides two-way ticket sync for Jira Service Management projects, typed API access for custom workflows and Catalyst, and the connection health check. It doesn't include prebuilt workflows (such as create issue, transition issue, or list projects), catalog or entity ingestion, inbound webhooks, or the Serval Forge app. The integration is marked Beta in the connect UI. Data Center exposes version 2 of the Jira REST API, while Cloud workflows are typically built against version 3, and issue search works differently on Data Center (a different search call with page-by-page offsets). Workflows written against the Cloud Jira integration will not run unmodified - rebuild them against this integration, or ask Catalyst to, and the correct Data Center endpoints will be used. When editing the connection, the Base URL field comes pre-filled with the stored host, and the API Token field shows a masked bullets-plus-last-4 placeholder behind a replace control. Leaving the token untouched or blank keeps the stored token, and leaving Base URL blank keeps the stored host. Fill in only the field you are rotating. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Jira Data Center integration. # JumpCloud Source: https://docs.serval.com/sections/integrations/jumpcloud Connect Serval to your JumpCloud directory to sync users and user groups, grant and revoke group membership for access management, and call the JumpCloud API from workflows. ## About JumpCloud JumpCloud is a cloud directory platform for identity, access, and device management. Serval connects to your JumpCloud organization with an administrator API key and works against both of JumpCloud's API versions (v1 and v2) behind the scenes. A single connection covers syncing users and user groups into Serval, granting and revoking group membership for access management, and calling any JumpCloud API endpoint from your workflows. **Authentication:** API key (a JumpCloud administrator API key, plus an optional Organization ID for multi-tenant admins) **Data sync:** Users, user groups, and group memberships are fully refreshed every 4 hours. Access changes (granting or revoking group membership) and all other API calls run on demand when a workflow executes, not on the sync schedule. ## What the JumpCloud integration enables | Capability | Description | | - | - | | Sync users | Imports your JumpCloud users into Serval, including each person's email, first and last name, manager, and whether the account is activated or suspended. | | Sync user groups | Imports your JumpCloud user groups so they can be used as access resources in Serval. Each group carries a single "Member" entitlement ("Member access to this JumpCloud user group"). Groups also serve as Serval's source of organization group information. | | Sync group memberships | Keeps track of which users belong to which JumpCloud groups, refreshed on the same 4-hour schedule. | | Provision and deprovision access | Adds or removes a user from a JumpCloud user group when an access workflow runs. The target user is matched by their email address. | | Generic API access | Workflows can call any endpoint in either JumpCloud API version (v1 or v2), with your API key applied automatically and your Organization ID included if configured. | | Connection health checks | Three built-in checks verify that your API key authenticates and that Serval can list users and groups (see Verifying the connection). | Anything defined in the [JumpCloud API](https://docs.jumpcloud.com/api/index.html) can be accessed through Serval. ## Get your credentials Serval connects with a JumpCloud **administrator API key**, generated from the admin's own profile in the JumpCloud Admin Portal. The key is tied to that individual administrator and inherits their permissions - for full functionality, the admin must be able to read users and groups and modify user group membership. See the [JumpCloud API documentation](https://docs.jumpcloud.com/api/index.html) for background. Go to the [JumpCloud Admin Portal](https://console.jumpcloud.com) and sign in as the administrator whose key Serval will use. Click your avatar (initials) in the top-right corner and choose "My API Key". Click "Generate New API Key" and copy the key immediately. If you are a multi-tenant (MTP/MSP) admin, also copy your Organization ID from Settings > Organization ID in the JumpCloud admin console. Single-organization admins can skip this. The API key is not shown again after you close the dialog. Copy it before closing, or you will need to generate a new one. Because the key inherits the individual administrator's permissions, pick an admin who can read users and groups and modify group membership. A key from a more limited admin will connect but fail later (see Gotchas). ## Connect in Serval In Serval, open the JumpCloud integration and start a new connection. A free-text display name for this connection inside Serval. Any value is accepted, including blank. Paste your JumpCloud administrator API key. This is a password-type field labeled "API Key \*". Submitting it blank shows the inline error "This field is required". There is no format validation - whatever you paste is saved as entered. Multi-tenant (MTP/MSP) admins only. The form describes it as: "Optional: For multi-tenant JumpCloud admins. Find this in Settings > Organization ID in the JumpCloud admin console." Single-organization admins should leave it blank. Submit the form. On success you will see the toast "JumpCloud connected successfully" and Serval automatically runs the connection health checks. If the connection fails, you will see the toast "Failed to connect service". Serval stores your API key as a secret. After saving, it is shown obfuscated (bullet characters plus the last 4 characters), and it is only ever sent to console.jumpcloud.com. When editing the connection later, re-enter the API Key in full every time you save - paste the complete key, not the obfuscated placeholder - and re-enter the Organization ID in full as well if you use one. Do not clear pre-filled fields you are not changing. A successful update shows the toast "JumpCloud updated". ## Verifying the connection After you connect, Serval runs three health checks against your JumpCloud organization and reports the result of each one. **Test JumpCloud Connection** - makes a minimal call to list groups, confirming your stored API key authenticates with JumpCloud. * Success: "Successfully authenticated with JumpCloud" * Failure: "Unable to connect to JumpCloud." followed by a status-specific message: * Invalid or expired key (401): "The API key is invalid or expired. Please verify your API key in the JumpCloud integration settings." * Insufficient permissions (403): "The API key is not authorized to access JumpCloud. Please ensure the key has been granted the necessary permissions." * JumpCloud server error (500/502/503): "JumpCloud returned a server error during authentication. This is likely a temporary issue - please try again later." **List JumpCloud Users** - lists up to 100 users (the reported count caps at 100). * Success: "Successfully listed \[number] users from JumpCloud" * Failure: "Unable to list users from JumpCloud." followed by a status-specific message: * 401: "The JumpCloud API key may be invalid or expired. Please verify your API key is correct." * 403: "The JumpCloud API key may not have the required permissions. Please check that the necessary privileges are granted." * 404: "The requested JumpCloud resource was not found. This may indicate missing permissions or an incorrect configuration." * 500/502/503: "JumpCloud returned a server error. This is likely a temporary issue with JumpCloud's API - please try again later." **List JumpCloud Groups** - lists up to 100 groups (the reported count caps at 100), with the same status-specific failure messages as List JumpCloud Users. * Success: "Successfully listed \[number] groups from JumpCloud" * Failure: "Unable to list groups from JumpCloud." All three checks can pass while access workflows still fail: the checks only read users and groups, but provisioning also requires the right to modify group membership. If add-to-group or remove-from-group workflows fail, confirm the administrator who owns the key can modify user group membership - and if you are a multi-tenant admin, that the Organization ID is set on the connection. ## Gotchas and troubleshooting Whenever you save changes to the connection settings - even if you are only changing something else - paste the complete API Key value rather than leaving the obfuscated placeholder, and for multi-tenant orgs re-enter the Organization ID as well. Do not clear pre-filled fields you are not changing. If the connection stops working after an edit, re-enter the API Key (and Organization ID, if you use one) in full and save again. Serval only scopes calls to a specific organization when an Organization ID is configured on the connection. A multi-tenant admin API key used without it can return missing data, not-found errors, or data from the wrong organization. Single-organization admins should leave the field blank. The ID is in Settings > Organization ID in the JumpCloud admin console. The key inherits that admin's permissions. For full functionality (user sync, group sync, and access provisioning), the administrator must be able to read users and groups and modify user group membership. A 403 from a health check means the key authenticates but lacks one of these rights. Add-to-group and remove-from-group workflows look up the target user in JumpCloud by their email address. The workflow fails with "No user found with email: \[email]" if there is no match, or "Multiple users found with email: \[email]" if there is more than one - the email must match exactly one JumpCloud user. For workflow authors using the generic API request actions: JumpCloud's [v1 API](https://docs.jumpcloud.com/api/1.0/index.html) wraps list results in an object containing a results list and a total count, while the [v2 API](https://docs.jumpcloud.com/api/2.0/index.html) returns lists directly. Both paginate with skip and limit parameters; 100 per page is the recommended size. Prefer v2 where an endpoint exists in both versions. Connecting: success shows "JumpCloud connected successfully"; failure shows "Failed to connect service". Saving changes to an existing connection: success shows "JumpCloud updated"; failures begin "Failed to install integration" or "Failed to update integration" (with detail appended when available), or fall back to "Failed to save configuration. Please try again.". *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your JumpCloud integration. # Justworks Source: https://docs.serval.com/sections/integrations/justworks Justworks is a PEO and HR platform for payroll, benefits, time off, and employee data. Serval connects to it with your own OAuth application so workflows can read and act on that data on demand. ## About Justworks Justworks is a Professional Employer Organization (PEO) and HR platform that covers payroll, benefits, time off, and employee data. The Serval Justworks integration is currently in **Beta**. Each Serval connection maps to exactly one Justworks company, and Serval automatically names the connection after the company it finds during setup. Serval only ever talks to Justworks's official API address (public-api.justworks.com). **Authentication:** Customer-provided OAuth 2.0 application. You supply your own Justworks Client ID and Client Secret, pick permission presets, and approve access in Justworks. Serval refreshes tokens automatically while the connection is in use - no manual token upkeep (see "Connection stops working after a long idle period" below for the one exception). **Data sync:** On-demand only. There are no background syncs, triggers, or webhooks. Workflows call the Justworks API when they run, and four automated health checks verify the connection. ## What the Justworks integration enables | Capability | Description | | - | - | | Workflow API access | Workflows can call any Justworks Public API operation on demand, covering company profile, members, payrolls, paystubs, payroll fees, deductions, time off, docs, and legacy ID translation. | | Employee and company data | Read company details, departments, offices, member profiles, contact info, and employment history. With extra presets, also compensation, date of birth, sex, and Tax ID (SSN). | | Payroll and paystubs | Read payroll runs, payroll fees, and paystub details (requires the Payroll & Paystubs preset). | | Time off | Read time off policies, requests, and balances. | | Deductions management | The only write preset: create, update, and cancel employee deductions (the Deductions preset's write scope includes read access). | | Connection health checks | Four automated checks verify company info, member list, department list, and time off policy access after connecting. | Anything defined in the [Justworks API](https://public-api.justworks.com/v1/docs) can be accessed through Serval. ## Get your credentials Serval connects using an OAuth application that you create in your own Justworks account. The application gives you a Client ID and a Client Secret, and it controls which permissions (scopes) Serval is allowed to request. Go to [Justworks Integrations settings](https://secure.justworks.com/integrations) and create an OAuth application for the Justworks Public API. Per Justworks's own API documentation, OAuth application creation is not self-service for every account - if you do not see an option to create one, ask the Justworks team or your Justworks representative to set one up. They will need your redirect URI (next step), the scopes you plan to use, and an application name. Add this redirect URI to your OAuth application: [https://svflow-auth-config.api.serval.com/justworks/oauth/callback](https://svflow-auth-config.api.serval.com/justworks/oauth/callback) Self-hosted Serval deployments use [https://svflow-auth-config.api.\<your-domain\>/justworks/oauth/callback](https://svflow-auth-config.api.\<your-domain\>/justworks/oauth/callback) instead. Enable every scope you intend to select in Serval (see the permission presets table below). A good baseline matches Serval's defaults: company.basic:read, company.detail:read, member.basic:read, member.detail:read, member.employment:read, and time\_off:read. You can give the application a name, logo URL, terms of service URL, and privacy policy URL. Justworks shows these on the authorization screen. Copy both values somewhere safe. You will paste them into Serval in the next section. Treat the Client Secret like a password. Serval stores both values to refresh tokens on your behalf, never displays the Client Secret again, and only ever shows the Client ID back to you obfuscated. ## Connect in Serval Find Justworks in the Serval app catalog (it is labeled Beta) and start the connection. A "Connect Justworks" dialog opens. Required. The field shows the placeholder "Enter your OAuth Client ID". Paste the Client ID from your Justworks OAuth application. Required. A password field with the placeholder "Enter your OAuth Client Secret". Under the "Permission Presets" header ("Select the permissions you need for your workflows"), the form explains: "Select the permissions your workflows will need. Make sure your OAuth application has these scopes enabled." Check at least one preset; you can expand any preset to see the exact scopes it grants. A live counter shows "\[number] permission(s) selected" - it counts individual scopes, not presets, so the four defaults show 6. | Preset | Description | Justworks scopes | Checked by default | | - | - | - | - | | Company Information | Read company details, departments, and offices | company.basic:read, company.detail:read | Yes | | Member Information | Read employee/member details and contact info | member.basic:read, member.detail:read | Yes | | Employment Data | Read employment history and job information | member.employment:read | Yes | | Time Off | Read time off policies, requests, and balances | time\_off:read | Yes | | Payroll & Paystubs | Read payroll runs and paystub details | payroll:read, paystub:read | No | | Compensation | Read pay rates, salary, and compensation details | member.pay:read | No | | Deductions (Read & Write) | Manage employee deductions | deductions:write | No | | Sensitive Member Data | Date of birth, sex, and Tax ID (SSN) | member.dob:read, member.sex:read, member.tax\_id:read | No | | Company Bank Account | Read company bank account information | company.bank\_account:read | No | The "Connect to Justworks" button stays disabled until both credential fields are filled and at least one preset is checked; submitting an incomplete form shows "Please fill in all required fields". Once you click it, your browser is sent to Justworks (payroll.justworks.com) to sign in and approve access. Finish this within 10 minutes of clicking the button. After you approve, Serval identifies your Justworks company and names the connection after it. The connection is now ready for workflows. Justworks connections cannot be edited in place - there is no update form, and the connect form always starts blank rather than pre-filling saved values. To rotate the Client Secret or change permissions, update the OAuth application in Justworks if needed, then reconnect and re-enter the Client ID, the Client Secret, and your preset selections from scratch. Keep the Company Information preset selected. Serval reads your company profile during setup to identify and name the connection, so connecting fails without company read access. ## Verifying the connection After connecting, Serval runs four health checks against your Justworks company: | Check | What it verifies | | - | - | | Get Company Information | Serval can read your company profile (Company Information preset - company.basic:read). On success: "Successfully retrieved company information for: \[name]". On failure: "Unable to read company information from Justworks." | | List Company Members | Serval can list employees - it samples one member (Member Information preset - member.basic:read). On success: "Successfully retrieved members list from Justworks (found \[number] member(s) in sample)". On failure: "Unable to list members from Justworks." | | List Company Departments | Serval can read department details, which are part of the detailed company profile (Company Information preset - departments populate with company.detail:read). On success: "Successfully retrieved departments list from Justworks (found \[number] department(s))". On failure: "Unable to list departments from Justworks." | | List Time Off Policies | Serval can read time off policies - it samples up to ten (Time Off preset - time\_off:read). On success: "Successfully retrieved time off policies from Justworks (found \[number] policy/policies)". On failure: "Unable to list time off policies from Justworks." | Failure messages also include a hint about the likely cause - see "What health check error hints mean" below. All four checks can pass while a workflow still fails. The checks only exercise the four default presets (company, member, employment, and time off data). If a workflow needs payroll, paystubs, compensation, deductions, sensitive member data, or bank account access, those presets must be selected at connect time and enabled on your Justworks OAuth application - no health check covers them. ## Gotchas and troubleshooting Serval requests exactly the scopes your selected presets map to, and Justworks rejects or narrows anything your OAuth application does not have enabled. After authorization, Serval records the scopes Justworks actually granted, which may be narrower than what you selected. If a health check fails with a permissions error, you will see: "This may be due to missing OAuth scopes. Please check that your Justworks application has the required permissions." Fix the scopes on the Justworks side, then reconnect. During setup, Serval reads your company profile to identify and name the connection. If the authorized token cannot read company information (for example, the Company Information preset was unchecked, or the OAuth app lacks company scopes), the connection fails with this message. Keep the Company Information preset selected and ensure company.basic:read is enabled on your OAuth application. The credentials you enter are held for only 10 minutes while you complete the Justworks authorization. If you click Connect but finish approving later than that, the connection fails with one of these messages. Start the connect flow again and complete the Justworks approval promptly. Existing Justworks connections cannot be edited in place - there is no update form, and the connect form never pre-fills saved values. To change permission presets or rotate the Client ID or Client Secret: update the OAuth application in Justworks if needed, then run the connect flow again and re-enter both credentials and the presets you want. Have everything on hand before you start, since the authorization must finish within 10 minutes. Per Justworks's API documentation, access tokens are valid for 24 hours and refresh tokens for 30 days. Serval refreshes the access token automatically whenever a workflow or health check calls Justworks, so an active connection stays healthy indefinitely. If the connection goes completely unused for more than 30 days, the refresh token expires and calls start failing with authorization errors - reconnect to restore it. Each failed check appends a hint to its "Unable to ..." message: * Unauthorized (401): "The OAuth token may have expired or been revoked. Please reconnect your Justworks integration." * Forbidden (403): "This may be due to missing OAuth scopes. Please check that your Justworks application has the required permissions." * Not Found (404): "The requested resource was not found. This may indicate a configuration issue." * Server error (500): "Justworks API is experiencing issues. Please try again later." * Anything else: "Error: \[details]" Every preset grants read-only access except Deductions (Read & Write), which lets workflows create, update, and cancel employee deductions (write access includes read). Also note the scope hierarchy: company.detail:read includes company.basic:read, and member.detail:read includes member.basic:read. Sensitive Member Data (date of birth, sex, and Tax ID, which is the SSN), Compensation, Payroll & Paystubs, and Company Bank Account are all unchecked by default. Only select them if your workflows genuinely need that data. A connection is bound to a single Justworks company and cannot reach across companies. If you manage more than one company, connect each one separately. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Justworks integration. # Kolide Source: https://docs.serval.com/sections/integrations/kolide Connect Serval to Kolide so workflows can inspect device trust posture, manage registrations, and call the Kolide device-security API. ## About Kolide Kolide is a device trust platform that verifies endpoint security posture before users authenticate to company resources. The Serval Kolide integration connects to `api.kolide.com` with a Kolide API token so workflows can list devices and people, review open issues, deprovision devices, and approve registration or exemption requests. The integration is marked **Beta** in Serval's connect UI. **Authentication:** API token (Bearer). Tokens start with `k2sk_`. Serval stores the token encrypted and sends it only to `api.kolide.com`. **Data sync:** On demand only. There is no background sync or asset ingestion. ## What the Kolide integration enables | Capability | Description | | - | - | | Device Trust bundle | Prebuilt workflows: list a user's devices by email, list their open issues, get device posture for a device ID, deprovision a device, and approve exemption or registration requests. | | Kolide API request | Typed access to the Kolide v1 API from custom workflows — devices, people, issues, checks, and admin operations your token can perform. | Install the **Device Trust** bundle from Workflows → Installable, or build custom workflows with the Kolide API request action. ## Get your credentials You need a Kolide API token created by a **Full Access** administrator. API key management requires Full Access admin privileges in Kolide. Navigate to the API Keys section in Kolide settings. Generate a token and copy it immediately. Kolide tokens start with `k2sk_`. Use the **API Token** password field in Serval's Kolide connect form. Treat Kolide API tokens like production credentials. A Full Access token can deprovision devices and approve security exceptions — scope access to the service account that owns the Serval connection. ## Connect in Serval In Serval, add the Kolide integration. It is labeled **Beta**. Paste your Kolide API token (`k2sk_…`) into the password field. Submit the form. Serval runs four health checks (below). When editing an existing connection, leave the token field as its obfuscated placeholder to keep the stored token, or paste a new token to rotate. ## Verifying the connection Four health checks run after you connect: 1. **Test Connection** — calls `GET /whoami`. Success: `Connected to Kolide organization "…"`. Failure: `Unable to authenticate with Kolide. Please check your API token.` 2. **List Devices** — fetches up to 10 devices. Failure usually indicates insufficient token permissions for device reads. 3. **List People** — fetches up to 10 people records. 4. **List Issues** — fetches up to 10 open issues. If authentication succeeds but list checks fail, the token is valid but may lack read scopes for that resource type. Regenerate the token with Full Access or adjust Kolide API key permissions. ## Gotchas and troubleshooting Standard Kolide roles without Developers access cannot reach the API Keys page. Mutating workflows in the Device Trust bundle ship with installer approval. Adjust approval procedures after install if your team wants different governance. Device Trust workflows resolve Kolide users by email address. Ensure requesters' corporate emails match their Kolide person records. Kolide returns paginated result sets. Prebuilt workflows page automatically; custom workflows should request additional pages until a short page is returned. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Kolide integration. # Kronos Workforce Central Source: https://docs.serval.com/sections/integrations/kronos Connect Kronos Workforce Central (UKG WFC) to Serval so workflows can call the WFC XML API — timekeeping, schedules, people data — with the cookie-session logon handled automatically. ## About Kronos Workforce Central Kronos Workforce Central (now UKG Workforce Central) is a self-hosted workforce management suite covering timekeeping, scheduling, accruals, and attendance. Its API is the Developer's Toolkit XML gateway: a single endpoint (`/wfc/XmlService`) that accepts XML request envelopes for every operation. This integration is for Kronos Workforce Central only. To connect UKG Pro (formerly UltiPro), UKG's cloud HR and payroll suite, use the [UKG Pro integration](/sections/integrations/ukg-pro). WFC authenticates with a session cookie: a `Logon` call returns a `JSESSIONID` cookie that every subsequent call must present. Serval performs that logon server-side and injects the session cookie into each request automatically — workflow authors never send credentials, never handle cookies, and never include `Logon`/`Logoff` requests in their envelopes. **Authentication:** A dedicated WFC account with XML API (Developer's Toolkit) access. Serval logs on server-side, maintains the session, and re-establishes it as needed. Sessions are reused for a few minutes at a time, so bursts of workflow calls share one logon instead of each performing their own. **Data sync:** On demand only. There is no background sync and no pre-built workflows; reads and writes happen inside workflow runs, and three health checks verify the connection. ## What the Kronos integration enables | Capability | Description | | - | - | | Kronos XML API request action | Send any Workforce Central XML request envelope from a workflow and get the raw XML response back, with the session established automatically. The per-object vocabulary (Timesheet, Punch, Person, Schedule, …) is documented in UKG's Developer's Toolkit reference guides for your WFC version. | | Connection health checks | Three built-in checks: credentials and session establishment (with per-cause failure diagnosis), the identity the session authenticates as, and the WFC server's clock and time zone. | ## Expose Workforce Central to Serval WFC is self-hosted, so Serval must be able to reach your XML gateway over HTTPS: * Expose the gateway (typically via a load balancer) and allow inbound traffic from Serval's egress IPs — contact **[support@serval.com](mailto:support@serval.com)** for the current list. * The host you expose must forward `Set-Cookie` headers from WFC unchanged. If your load balancer adds its own affinity cookies, Serval replays them together with the WFC session cookie automatically. * Point the gateway directly at the WFC XML service. An SSO or portal front that redirects the logon request will fail the connection with a redirect error. ## Get your credentials Use a dedicated service account (for example, serval-integration) rather than a person's login, and exempt it from password-expiration policies if possible — if the password rotates, the connection fails until it is updated in Serval. The account's Function Access Profile must permit XML API / Developer's Toolkit access, plus access to the data your workflows will touch (for example, timekeeping for Timesheet requests). The hostname (and optional port or path prefix) where `/wfc/XmlService` is reachable from the internet, e.g. `kronos.example.com` or `lb.example.com/kronos`. ## Connect in Serval In Serval, add the **Kronos Workforce Central** integration to open the connect form. All three fields are required. The host where your WFC XML gateway is reachable — no `https://`. A port or path prefix is allowed: `kronos.example.com`, `kronos.example.com:8443`, or `lb.example.com/kronos`. The host is lowercased; a path prefix keeps its exact case. The dedicated WFC account with XML API access. The account's password. Stored encrypted; used only by Serval's backend to establish the WFC session. When you reopen the connection to edit it, the saved password appears masked. Leaving it untouched keeps the stored password, so you can change the host or username without re-entering it. ## Verifying the connection **Test Kronos Connection** — authenticates and completes a System Ping over the established session. * Pass: "Successfully authenticated with Workforce Central and completed a System Ping over the session." * Fail: the message surfaces the server-side logon diagnosis, which distinguishes the possible causes — an unreachable host, a redirect (an SSO or portal front), an answer that isn't a Workforce Central XML envelope (wrong host or path), or rejected credentials with WFC's own error code. **Verify Session Identity** — loads the logged-on account's identity (`CurrentUser` `LoadIdentities`), confirming the session authenticates as the expected service account and that basic API function access (API.Common) is granted. * Pass: "The session authenticates as person number \[number]." **Check Server Time** — reads the WFC server's date, time, and time zone (`ServerTime` `GetServerTime`). For a timekeeping system, clock skew or an unexpected server time zone silently corrupts punch data — this check makes it visible. * Pass: "Workforce Central server time is \[date and time] (\[time zone])." ## Using the XML API from workflows Send a complete `Kronos_WFC` envelope and check each `Response` element's `Status` attribute: ```xml theme={null} ... ``` WFC answers HTTP 200 even for failed requests — the outcome is the `Status` attribute (`Success` or `Failure`) on each `` element, with detail in `` elements (`ErrorCode`, `Message`). Workflows must check `Status`, not the HTTP status. ## Gotchas and troubleshooting Serval establishes and maintains the session automatically. An envelope containing a Logon request would carry credentials workflow code should never hold — leave authentication to the connection. The gateway host must point directly at the WFC XML service. A redirect on logon usually means the host is an SSO front or a portal path — expose `/wfc/XmlService` directly instead. Verify the account's Function Access Profile actually permits XML API (Developer's Toolkit) access — a valid password without API access is still rejected. The connection error includes WFC's own error code and message when the gateway provides one. A proxy or load balancer in front of WFC may be stripping Set-Cookie headers. Serval needs the logon response's cookies verbatim to authenticate follow-up calls. Serval reuses each session for a few minutes and then logs on again, so a stale session heals itself within moments. If an app-server restart or an admin session purge lands mid-window, the next few calls can see a WFC session error before the refresh — retrying the workflow step succeeds. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Kronos Workforce Central integration. # LaunchDarkly Source: https://docs.serval.com/sections/integrations/launchdarkly Connect LaunchDarkly to Serval to list projects, inspect and toggle feature flags, browse environments, and review audit history through Serval workflows. ## About LaunchDarkly LaunchDarkly is a feature management platform for feature flags, targeting rules, environments, and experimentation. Serval connects to your LaunchDarkly account with a single API access token, so workflows can look up projects and flags, toggle flags, and pull audit history on your behalf. The token's role on the LaunchDarkly side fully determines what Serval can read and write - Serval requests no permissions of its own, and it only ever sends the token to LaunchDarkly's standard API host, app.launchdarkly.com. **Authentication:** API access token (a personal or service access token created in LaunchDarkly's Authorization settings). **Data sync:** On demand only. Serval reads or writes LaunchDarkly data while a workflow step is running. There is no background sync and no webhooks. ## What the LaunchDarkly integration enables | Capability | Description | | - | - | | List LaunchDarkly Projects | List all projects in your LaunchDarkly account, with project keys, names, and metadata. | | List Feature Flags | List the feature flags in a project, with keys, names, descriptions, and current status. | | Get Feature Flag Details | Get full detail on a specific flag, including its variations, targeting rules, and per-environment configuration. | | Toggle Feature Flag | Turn a feature flag on or off in a specific environment. Runs require approval by default. | | List Environments | List all environments for a project, with keys, names, and configuration. | | List Audit Log Entries | Retrieve the 20 most recent audit log entries showing who changed what and when. | Anything defined in the [LaunchDarkly API](https://launchdarkly.com/docs/api) can be accessed through Serval. ## Get your credentials Serval needs one credential: a LaunchDarkly API access token. You can use a **personal access token** (its permissions follow the member who created it) or a **service access token** (fixed permissions that survive membership changes, but requires a LaunchDarkly Enterprise plan). LaunchDarkly's official guide is [Creating API access tokens](https://launchdarkly.com/docs/home/account/api-create); for the difference between token types, see the [API access tokens overview](https://launchdarkly.com/docs/home/account/api). In LaunchDarkly, click the gear icon in the left sidebar to open Organization settings, then click **Authorization**. In the **Access tokens** section, click **Create token**. Give the token a human-readable name and assign a Role (Reader, Writer, Admin, Owner, a custom role, or an inline policy). Check **This is a service token** if you want a service token (Enterprise only) whose permissions do not change with the creating member. Click **Save token**. Copy the token right away - it is visible exactly once. If you leave or refresh the page it is obscured permanently and you must create a new one. For Serval's health checks to pass, the token needs at minimum read access to projects. Add read access to feature flags, environments, and account members to satisfy the remaining checks - a Reader role covers all of these. If you plan to use the Toggle Feature Flag workflow, the token also needs write access to flags (for example a Writer role or an equivalent custom role). For a durable team connection, prefer a service token where available. A personal token's permissions follow the member who created it and stop working if that member leaves your LaunchDarkly account. ## Connect in Serval In Serval, find the LaunchDarkly integration and open its connect form. Paste the token into the **API Access Token** field (required) - "A personal or service access token from your LaunchDarkly Authorization settings". Paste it exactly as LaunchDarkly displayed it, with nothing added before or after. Leaving the field empty shows "This field is required". Submit the form. If the connection cannot be created you may see "Failed to connect service" or "Failed to install integration". Serval does not contact LaunchDarkly when you submit the form, so an invalid or expired token will still connect "successfully". Always check the health check results after connecting - when you connect from an application's setup form, Serval runs the health checks automatically right after the connection saves. When you later edit the connection settings, the saved token displays as an obfuscated value (bullets plus the last 4 characters) next to a pencil icon - or a **Replace** button if you are in the configure dialog - and the field shows the placeholder "Enter new value" once you start replacing it. Do not save the settings form without pasting the complete token again - whenever you edit the connection (for example to rotate the token), always re-enter the full token before saving, then re-run health checks. ## Verifying the connection Serval runs four health checks against your LaunchDarkly account: | Health check | What it verifies | Success message | Failure message | | - | - | - | - | | Test LaunchDarkly Connection | Basic connectivity and authentication by fetching projects. | "Successfully connected to LaunchDarkly" | "Unable to connect to LaunchDarkly. Please verify your API access token is correct and has not expired." | | List Feature Flags | Permission to read feature flags in your first project. | "Successfully listed feature flags from project "\[project key]"" | "Unable to list feature flags from LaunchDarkly. Please verify your access token has read permissions for feature flags." | | List Environments | Permission to read environments in your first project. | "Successfully listed \[number] environment(s) from project "\[project key]"" | "Unable to list environments from LaunchDarkly. Please verify your access token has read permissions for environments." | | List Account Members | Permission to read account members. | "Successfully listed account members (\[number] returned)" | "Unable to list account members from LaunchDarkly. Please verify your access token has read permissions for account members." | If your account has no projects yet, the flag and environment checks still pass with "Connected to LaunchDarkly but no projects found to list flags from" and "Connected to LaunchDarkly but no projects found to list environments from". All four health checks are read-only, so they can be fully green while the Toggle Feature Flag workflow still fails. If toggling a flag returns a permission error, your token has read access but lacks write access to flags - recreate or re-role the token with write permission (for example Writer). ## Gotchas and troubleshooting The connect form accepts any non-empty value without contacting LaunchDarkly, so a typo'd, expired, or revoked token only surfaces when health checks run. If "Test LaunchDarkly Connection" fails, create a fresh token in LaunchDarkly's Authorization settings and reconnect. Also confirm the token has at least read access to projects - that is the minimum for the connection test. Serval sends the stored token to LaunchDarkly exactly as you entered it, which is what LaunchDarkly expects. Do not type "Bearer ", "api-key ", or anything else in front of the token in the form - any added text makes every request fail as unauthorized. When updating the connection, always paste the complete token again before saving - never save the settings form with the token field untouched or cleared. If the connection stops working after an edit, re-enter a valid token and re-run health checks. The prebuilt Toggle Feature Flag workflow installs with installer approval required by default, so flag toggles are gated behind the installer's approval out of the box. The five read-only prebuilt workflows (list projects, list flags, get flag details, list environments, list audit log entries) install with no approval required. The integration only reaches LaunchDarkly's standard instance at app.launchdarkly.com. Accounts on LaunchDarkly's federal instance (app.launchdarkly.us) or EU endpoints cannot connect through this integration. A personal token's permissions follow the member who created it and die with that member's account. A service token's permissions are fixed at creation and survive membership changes, but service tokens require LaunchDarkly Enterprise. Prefer a service token for a durable team connection where available. If your team builds custom workflows that modify flags through the generic LaunchDarkly API action, those updates must use LaunchDarkly's JSON Patch format (a list of operations, optionally with a comment attached). LaunchDarkly's alternative "semantic patch" format will not work through this integration. The feature flag list supports fuzzy search across flag key, name, and description - the search term should not be wrapped in quotes. Other areas of the LaunchDarkly API, such as segments, do not support that search filter at all; workflows there must page through results and filter afterward. Do not assume one area's filter format works in another. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your LaunchDarkly integration. # Active Directory (on-prem) Source: https://docs.serval.com/sections/integrations/ldap-ad Connect Serval to your on-premises Microsoft Active Directory (or any LDAP v3 directory) for user and group sync, group-based access management, and directory automation from workflows. ## About Active Directory (on-prem) The Active Directory (on-prem) integration connects Serval directly to your on-premises Microsoft Active Directory - or another LDAP v3 directory - for user and group sync, group-based access management, and full directory operations from workflows. Unlike SaaS integrations, there is no OAuth and no vendor API: Serval speaks the LDAP protocol directly from the Serval worker, which dials only the server URL you configure. On self-hosted workers configured with local credentials, the worker reads your bind credentials from its own local store at execution time instead of fetching them from Serval's cloud. Every operation uses a fresh, short-lived connection with TLS 1.2 as the minimum version. **Authentication:** LDAP simple bind with a dedicated service account (Server URL, Base DN, Bind DN, Bind Password, plus an optional CA certificate). Secrets are stored encrypted. **Data sync:** Background full sync - users every 4 hours, groups every 16 hours. LDAP has no change-log API, so there is no delta sync; each cycle re-reads the directory in full. Workflow actions (search, group changes, entry edits, password resets) run on demand. ## What the Active Directory (on-prem) integration enables | Capability | Description | | - | - | | User directory sync | Full sync of AD users into Serval every 4 hours. Only user objects with a mail or userPrincipalName are ingested; computer accounts are excluded; disabled accounts are detected from AD's userAccountControl disable flag. | | Group sync | Full sync of AD groups every 16 hours as Serval resources (the group's DN is the stable external ID), usable as an org group info source. | | Access management | A single "Member" entitlement per group ("Member access to this Active Directory group"). Serval resolves the target user's email to a directory DN, then adds or removes that DN on the group's member attribute. | | User and group search from workflows | Single-page searches (capped at 1,000 entries by default) and paged "search all" variants that return every matching entry. | | Group member listing | Lists group members with nested groups expanded recursively (AD's matching-rule-in-chain), excluding computer accounts. A name-based variant resolves a group's cn to a DN first; name-based membership actions also resolve a user's sAMAccountName. | | Directory entry CRUD | Create, modify (add, replace, delete attributes - binary values supported), delete, and rename or move entries from workflows. | | Password reset | Sets AD's unicodePwd attribute with the required quoted UTF-16LE encoding. Requires an encrypted connection (LDAPS or StartTLS). | | Shipped workflow: Get AD Extension Attributes for User | Installable workflow that looks up a user by email (via a configurable lookup attribute) and returns any populated extensionAttribute1-extensionAttribute15, plus the DN and sAMAccountName. | ## Get your credentials You need a dedicated Active Directory service account for Serval to bind with, your domain controller's URL (ldaps\:// on port 636 recommended), your domain's Base DN, and - if your domain controller's TLS certificate is issued by an internal CA - the root CA certificate in PEM format. Microsoft's guide to enabling LDAPS is here: [Enable LDAP over SSL with a third-party certification authority](https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/enable-ldap-over-ssl-3rd-certification-authority). Open Active Directory Users and Computers and create a new user in an appropriate OU (for example `CN=svc-serval,OU=ServiceAccounts,DC=corp,DC=example,DC=com`). Set a strong, non-expiring password. Grant the account read access to the OUs containing your users and groups. Delegate write access on group objects only if Serval should manage group membership, and Reset Password rights only if Serval should reset passwords. Run `(Get-ADDomain).DistinguishedName` in PowerShell on a domain-joined machine, or `ldapsearch -x -H ldap://dc01.corp.example.com -s base namingContexts` from Linux. Use LDAPS (ldaps\://, port 636, recommended) or StartTLS (ldap\://, port 389). If LDAPS is not yet enabled on the domain controller, provision a server certificate first (for example via AD CS auto-enrollment). If the domain controller's certificate is issued by an internal CA, export the root CA certificate in PEM format - for example `certutil -ca.cert ca.pem` on the DC, or `openssl s_client -connect dc01.corp.example.com:636 -showcerts` to capture the chain. Convert DER to PEM with `certutil -encode ca.cer ca.pem` or `openssl x509 -inform der -in ca.cer -out ca.pem`. Before pasting it into Serval, confirm `openssl s_client -connect dc01.corp.example.com:636 -CAfile ca.pem` reports "Verify return code: 0 (ok)". The host running the Serval worker must be able to resolve and reach the domain controller on the chosen port (636 or 389). For on-prem AD this usually means a hybrid self-hosted worker inside your network, or VPN/Direct Connect routing from the Serval deployment. See [Private Network Access](https://docs.serval.com/sections/self-hosting/private-network-access). You need the **issuing CA's certificate** (or the full chain), not the domain controller's own server certificate. Pasting the wrong certificate is the most common cause of TLS verification failures. A dedicated account named for its purpose (for example `svc-serval`) makes it easy to audit Serval's directory activity later. ## Connect in Serval **Server URL** (required) - for example "ldap\://10.0.1.4:389 or ldaps\://10.0.1.4:636". As the helper text explains: "ldaps\:// uses implicit TLS (port 636); ldap\:// upgrades via StartTLS by default". Anything else is rejected with "Must start with ldap\:// or ldaps\://" (the backend enforces the same: "serverUrl is required", "serverUrl must start with ldap\:// or ldaps\://"). Your integration instance is identified and displayed by this URL. **Base DN** (required) - for example "DC=example,DC=com". Leaving it empty fails with "baseDn is required". **Bind DN** (required) - the full DN of the service account, for example "CN=svc-connector,OU=ServiceAccounts,DC=example,DC=com". Helper text: "Service account used to authenticate with LDAP". Leaving it empty fails with "bindDn is required". **Bind Password** (required) - the service account password, stored encrypted. Leaving it empty on first connect fails with "bindPassword is required". **CA Certificate** - optional PEM-encoded certificate beginning with "-----BEGIN CERTIFICATE-----". Helper text: "Optional PEM-encoded CA certificate for verifying the LDAP server". Required in practice whenever your domain controller uses an internal CA. A value that cannot be parsed causes every connection (including the health checks) to fail with "ldap: failed to parse CA certificate". **Allow plaintext LDAP** - checkbox, off by default: "Skip StartTLS upgrade for ldap\:// connections. Credentials are sent unencrypted - only enable if TLS is handled at the network layer (e.g. VPN or tunnel)." As the helper text notes: "When disabled (default), ldap\:// connections are automatically upgraded to TLS via StartTLS." When you later edit the connection, Bind Password and CA Certificate display masked (bullets plus the last 4 characters). Leave them untouched to keep your stored secrets - Serval only replaces a secret when you actually type a new value. ## Verifying the connection After connecting, Serval runs three health checks: | Check | What it verifies | On success | On failure | | - | - | - | - | | Test LDAP Connection | The server is reachable and the bind credentials are valid (connect, bind as the service account, close). | "Successfully connected and authenticated to LDAP" | "Unable to connect to LDAP server. Verify the server URL is reachable and credentials are correct." If the server responds but the test still fails: "LDAP server responded but connection test failed. Check your bind credentials." | | Search Users | The service account can search for users - runs a one-entry search and reports a sample user DN. | "Successfully searched users in the directory" | "Unable to search users. Check that the base DN is correct and the service account has read permissions." | | Search Groups | The service account can search for groups - runs a one-entry search and reports a sample group DN. | "Successfully searched groups in the directory" | "Unable to search groups. Check that the base DN is correct and the service account has read permissions." | All three checks green but access provisioning fails? The health checks only test **read** access. Adding or removing group members requires delegated **write** access on the target group objects - and provisioning also fails if the user's email matches zero (or more than one) directory entry across mail and userPrincipalName. ## Gotchas and troubleshooting All LDAP traffic originates from the Serval worker's built-in LDAP proxy, which dials your configured Server URL directly with a 10-second connection timeout. The worker host needs network routing and DNS resolution to the DC on port 636 (LDAPS) or 389 (LDAP/StartTLS) - typically via a hybrid self-hosted worker inside your network, or VPN/Direct Connect/Transit Gateway connectivity. On self-hosted workers configured with local credentials, the bind password is read from the worker's local store at execution time. See [Private Network Access](https://docs.serval.com/sections/self-hosting/private-network-access). If you share this connection with another team, that team needs its own self-hosted worker to use it. Set one up from that team's **Settings → Workers** page. ldaps\:// uses implicit TLS; ldap\:// is automatically upgraded via StartTLS unless "Allow plaintext LDAP" is enabled. Minimum TLS version is 1.2. Domain controllers using an internal CA will fail certificate verification until you paste the **root CA** (or full chain) in PEM format into the CA Certificate field - the issuing CA's certificate, not the DC's own server certificate. User sync only ingests user objects that have a mail or userPrincipalName value, and group-member sync skips entries with neither (this deliberately excludes built-in accounts like Administrator and Guest). Computer accounts are always excluded. Many on-prem directories don't populate mail for everyone - userPrincipalName is the fallback for both sync and access provisioning, and provisioning fails if a user's email matches zero or multiple directory entries. LDAP has no change-log API, so there is no delta sync: groups re-sync in full every 16 hours and users every 4 hours. Newly created AD groups or membership changes can take up to one full cycle to appear in Serval unless you trigger a sync manually. Password resets write AD's unicodePwd attribute (quoted, UTF-16LE encoded by Serval). Active Directory rejects these changes over plaintext, so password resets fail if "Allow plaintext LDAP" is enabled without TLS. The single-page search actions default to a 1,000-entry limit, and when the server reports the limit was exceeded, the truncated result set is returned **without an error**. Use the paged "search all" variants ([RFC 2696](https://www.rfc-editor.org/rfc/rfc2696) paged results, 1,000 per page) when you need every entry. Group member queries use Microsoft's [matching-rule-in-chain](https://learn.microsoft.com/en-us/windows/win32/adsi/search-filter-syntax), so members of nested groups are included transitively and computer accounts are filtered out. Non-AD LDAP servers (such as OpenLDAP) don't support this rule, making group-member operations effectively AD-specific. Plain user/group search and entry CRUD work against generic LDAP, and deactivation detection simply reports active when userAccountControl is absent. On the edit screen, Bind Password and CA Certificate appear as bullets plus the last 4 characters. Submitting the form with those fields untouched preserves the stored secrets - only typed-in new values replace them. The backend configuration accepts user and group search-base overrides that scope searches more narrowly than the Base DN (falling back to Base DN when empty), but the connect form does not expose them - it only collects Server URL, Base DN, Bind DN, Bind Password, CA Certificate, and the plaintext toggle. Every search filter is validated before it is sent - invalid filters are rejected with "invalid LDAP filter: …". Searches run with a 30-second server-side time limit, and request payloads are capped at 1 MB. Workflow builders should escape user-supplied filter values with the provided escape helper. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Active Directory (on-prem) integration. # Linear Source: https://docs.serval.com/sections/integrations/linear Sync Serval tickets to Linear issues and automate issue management in your Linear workspace with Serval workflows. ## About Linear Linear is the issue tracker many engineering and product teams use to plan and ship work. Serval's Linear integration connects to your Linear workspace so Serval tickets and Linear issues stay in sync - with comments attributed to the original requester rather than a generic app identity - and ships 15 installable workflows for issue management and workspace lookups. All traffic goes to Linear's GraphQL API (host: api.linear.app). **Authentication:** OAuth 2.0 - sign in with the Serval-managed Linear OAuth app (recommended), or bring your own Linear OAuth application. Both modes request **read** and **write** by default. Select **Allow access to Linear Customers** to also request **customer:write**, which includes reading and writing customer data. Customer access is optional and off by default. Tokens are refreshed automatically. **Data sync:** Two-way ticket syncing runs in the background once a Linear team is connected as a ticket channel: Serval regularly checks the team for new and updated issues and comments and pulls them in, and pushes Serval-side changes out to Linear as they happen. Workflow actions run on demand, calling Linear at the moment they run. ## What the Linear integration enables | Capability | Description | | - | - | | Ticket syncing | Two-way sync between Serval tickets and Linear issues. Outbound, Serval creates and updates issues, adds comments (duplicates are automatically detected and reused), maps issue states, and applies SLA timestamps - and issues and comments show up in Linear attributed to the original requester. Inbound, Serval regularly checks the connected Linear team and pulls new and updated issues and comments into Serval. | | Issue management workflows | 11 installable workflows: Get Linear Issue Info (by URL, key like ENG-123, or ID), Add Comment to Linear Issue, Add Label to Linear Issue, Archive Linear Issue, Delete Linear Issue, Clear Linear Issue Priority, Move Linear Issue to Different Cycle, Reopen Issue Based on Related Issues, Update Linear Issue Description (markdown supported), Update Linear Issue Title, and Update Linear Issue Project. Destructive workflows (archive, delete, clear priority, move cycle, reopen, update project) default to requiring installer approval. | | Workspace workflows | 4 installable workflows: Get Linear User ID (email to user ID, including suspended users), Invite Linear User (requires installer approval), List Linear Labels (active global and team labels), and List Linear Teams. | | Generic API access | Serval workflows can call any operation in Linear's GraphQL API through the integration, with authentication injected automatically and cursor-based pagination supported. See Linear's [GraphQL API guide](https://developers.linear.app/docs/graphql/working-with-the-graphql-api). | | Customer workflows (optional) | Read and manage Linear Customers and attach customer requests to issues with `customerNeedCreate`. Enable **Allow access to Linear Customers** when connecting or reconnecting. | | Access management (deprecated for new installs) | Built-in workflows that invite a user with the Admin or Member role, or suspend a user by email. Existing installs keep working, but this is deprecated for new installs - see Gotchas and troubleshooting below. | Anything defined in the [Linear API](https://developers.linear.app/docs) can be accessed through Serval. ## Get your credentials No setup is needed in Linear. Serval uses its own Linear OAuth application, so connecting is just an authorization: you're sent to Linear's consent screen, you approve **read** and **write** access plus customer access if selected, and Serval records your Linear workspace name and ID as the connected instance. Tokens are refreshed automatically from then on. If your organization prefers to own the OAuth application, create one in your Linear workspace and hand its credentials to Serval. Linear's official guide is the [OAuth 2.0 authentication documentation](https://developers.linear.app/docs/oauth/authentication). In Linear, go to **Settings → API → Applications** and [create a new OAuth application](https://linear.app/settings/api/applications/new), or open an existing one. Copy the **Callback URL** shown in Serval's connect dialog and paste it into the application's **Callback URLs** list. Linear requires an exact match between the registered Callback URL and the one Serval uses during authorization. Use the Copy button in Serval's dialog and paste it verbatim - a retyped or partial URL will be rejected. Save the application, then copy its **Client ID** and **Client secret** from the application's settings page. Linear shows the client secret only once, at creation. If you no longer have it, regenerate the secret on the application's settings page. Back in Serval, enter the optional Display name plus the Client ID and Client secret, and click Connect to run the OAuth authorization. ## Connect in Serval If your workflows need to read or manage Linear Customers or attach customer requests to issues, select **Allow access to Linear Customers**. Leave it unchecked for the default **read** and **write** permissions. This option applies to both connection methods and requests **customer:write**, which includes customer reads and writes. See Linear's [customer access scopes](https://linear.app/developers/agents#customer-access-scopes). The connect dialog offers two options: **"Sign in with Linear (OAuth)"** (tagged "Recommended") - "Connect using the Serval-managed Linear OAuth app." - and **"Use your own Linear OAuth app"** - "Connect with a Linear OAuth application owned by your workspace." Click **Sign in with Linear (OAuth)** and approve the request on Linear's consent screen. If the sign-in can't start, the dialog shows "Failed to initiate Linear OAuth" - try again or contact support. The custom-app form contains: * **Callback URL** - read-only, with a Copy button. Register this value on your Linear OAuth application before connecting. * **Display name** (optional) - "A friendly name shown in Serval - you choose this." Placeholder: "My Company Linear". * **Client ID** (required) - "Found on the application's settings page in Linear, under OAuth." Serval rejects a blank value with "clientId is required". * **Client secret** (required, hidden as you type) - "Linear only shows this once when the app is created - if you don't have it, regenerate the secret on the application's settings page." Serval rejects a blank value with "clientSecret is required". The Connect button stays disabled until both required fields are filled in. If the connection can't start, you'll see "Failed to initiate custom Linear app". Approve the request on Linear's consent screen. You have **10 minutes** from submitting the form - after that the attempt fails with "Invalid or expired OAuth state" and you must resubmit. If Linear rejects the exchange (for example, a mismatched Callback URL or wrong secret), you'll see "Failed to exchange code for token". On success, Serval records your Linear workspace name and ID as the connected instance. Existing connections keep their current permissions. To add customer access, reconnect, select **Allow access to Linear Customers**, and approve the updated request in Linear. Serval restores the customer-access checkbox from the permissions already granted when you reconnect. When reconnecting a bring-your-own-app install, the Display name and Client ID are pre-filled from your existing setup, but the Client secret is never pre-filled - re-enter it (or regenerate it in Linear if you've lost it). ## Verifying the connection The Linear integration runs three health checks: * **Test Linear Connection** - verifies the integration is connected and the OAuth token is valid by reading a single user from your workspace. * Success: "Successfully authenticated with Linear (found \[number] user)" * Failure: "Unable to authenticate with Linear. Please verify the integration is still connected and the OAuth token has not been revoked." * **List Linear Users** - checks that Serval can read users from the connected workspace. * Success: "Successfully listed Linear users (sample size: \[number])" * Failure: "Unable to list users from Linear. Please verify the integration has the read scope and has not been disconnected." * **List Linear Teams** - checks that Serval can read teams from the connected workspace. * Success: "Successfully listed Linear teams (sample size: \[number])" * Failure: "Unable to list teams from Linear. Please verify the integration has the read scope and has not been disconnected." All three checks exercise general read access only; they do not verify customer permissions. To verify customer access, run a workflow that reads Linear Customers. If every check is green but a workflow that invites or suspends a workspace member fails, the cause is usually that this integration deliberately has no admin scope - see **Workspace membership management requires Linear Admin** under Gotchas and troubleshooting. ## Gotchas and troubleshooting If a workflow returns `403 customer:read or customer:write required`, reconnect the Linear integration, select **Allow access to Linear Customers**, and complete authorization in Linear. The **customer:write** permission covers both reading customers and attaching customer requests to issues. The Linear Admin connector is not required for these operations. Inviting and suspending users requires the companion **[Linear Admin](/sections/integrations/linear-admin)** integration. Enabling customer access on the standard Linear connection does not grant admin permissions. The older built-in access-provisioning workflows on this integration (invite with the Admin or Member role, suspend by email) still work for existing installs but are deprecated for new ones; their role mapping accepts only "Admin", "Member", or "User" - any other role name fails. Serval connects to Linear in app-actor mode, which is what allows synced issues and comments to appear in Linear as the person who raised the ticket rather than as a generic app identity. This applies to both the Serval-managed and bring-your-own connection options. Linear requires an exact match between the Callback URL registered on your OAuth application and the one Serval uses during both authorization and token exchange, and it rejects relative URLs. Always copy the value from Serval's connect dialog verbatim. Separately, Linear displays the client secret only once at app creation - if it's lost, regenerate it on the application's settings page and reconnect with the new value. Submitted credentials are held for only 10 minutes while you complete Linear's consent screen. If the window passes, the attempt fails with "Invalid or expired OAuth state". Re-open the connect dialog and submit the form again, then complete the authorization promptly. Serval refreshes OAuth tokens automatically shortly before they expire, and older long-lived tokens on Serval-managed connections are upgraded to refreshable tokens transparently. The one case that requires action: a bring-your-own-app connection whose token expires with no refresh token available fails with "custom Linear app access token expired and no refresh token available; reconnect required". The fix is to reconnect the integration. During ticket sync, SLA-breach timestamps are written to a Linear issue only when that issue is in an unstarted or started state. For issues in any other state, the timestamp is silently dropped rather than causing a sync error. Linear authorization codes are single-use, and Linear expects OAuth credentials as form parameters in the request body. Tooling that tries a different credential style first and then retries will burn the code on the failed attempt, producing "invalid\_grant: authorization code is invalid" even with correct credentials. Serval sends credentials correctly on the first attempt - this only matters if you debug the token exchange with your own tooling. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Linear integration. # Linear Admin Source: https://docs.serval.com/sections/integrations/linear-admin Connect Linear with admin access so Serval can invite, suspend, and unsuspend users and manage workspace membership in your Linear organization. ## About Linear Admin Linear Admin is the admin-scoped companion to the [Linear integration](/sections/integrations/linear). Linear does not allow the admin permission on the connection mode the ticket-sync Linear integration uses, so admin operations - inviting, suspending, and unsuspending users - live on this separate connection. Ticket syncing stays on the regular Linear connection; Linear Admin owns user provisioning and workspace-membership management. Workflow API requests are restricted to Linear's API host, api.linear.app. **Authentication:** OAuth 2.0, either through the Serval-managed Linear app ("Sign in with Linear (Admin OAuth)", recommended) or your own Linear OAuth application. Both request the read, write, and admin permissions, so a Linear workspace admin must authorize the connection. **Data sync:** No background or scheduled sync. Health checks, user-management workflows, provisioning, and API calls all run on demand. Access tokens are refreshed automatically whenever they are expired or within 5 minutes of expiry. ## What the Linear Admin integration enables | Capability | Description | | - | - | | User provisioning via Access Management | Two app access roles are registered for Linear: **Admin** (organization administrator) and **Member** (standard member). Provisioning invites the requested user to your Linear organization with the mapped role - "Admin" grants Linear's admin role, "Member" or "User" grants the standard member role. The user receives an invitation email from Linear and must accept it; accounts are not created directly. | | User deprovisioning (suspend) | Finds the target user by email (including already-suspended users) and suspends their Linear account. Deprovisioning suspends rather than deletes; a built-in unsuspend workflow can reactivate the account. | | Built-in user-management workflows | Four admin workflows for use in any Serval workflow: "Get Linear User ID (Admin)", "Invite Linear User (Admin)" (invites with the workspace default role), "Suspend Linear User (Admin)", and "Unsuspend Linear User (Admin)". | | Admin-level Linear API access | The "Linear Admin API request" action gives workflows full admin-level access to Linear's GraphQL API, with authentication handled automatically. | | Connection health checks | Three read-only checks verify authentication, confirm admin access was actually granted, and confirm users (including suspended ones) can be listed. | Anything defined in the [Linear GraphQL API](https://linear.app/developers/graphql) can be accessed through Serval. ## Get your credentials No Linear-side setup is needed. Serval's own Linear app handles the OAuth flow - you just approve it on Linear's consent screen. The person who authorizes the connection must be a **Linear workspace admin**. The connection requests admin access, and Linear only grants it if an admin approves. If this option is not shown in your environment (for example, on self-hosted deployments), use your own Linear OAuth app instead. You need a Linear OAuth application owned by your workspace, plus its Client ID and Client secret. The application needs no special admin configuration - admin access is requested when you authorize - but the person authorizing must be a workspace admin. See Linear's [OAuth 2.0 authentication guide](https://linear.app/developers/oauth-2-0-authentication) for background. In Linear, open **Settings**, then **API**, then **Applications**, and create a new OAuth application ([direct link](https://linear.app/settings/api/applications/new)), or open an existing one. Copy the **Callback URL** shown in Serval's connect dialog (use the **Copy** button) and paste it into the application's **Callback URLs** list. Linear requires an exact match between this URL and the value Serval sends. Save the application, then copy the **Client ID** and **Client secret** from the application's settings page. Linear shows the client secret **only once**, at creation. If you no longer have it, regenerate it from the application's settings page - and note that regenerating invalidates the old secret for any existing connections using it. ## Connect in Serval When you connect Linear Admin, Serval shows a selection screen with two options. Select **Sign in with Linear (Admin OAuth)** (marked **Recommended**): "Connect using the Serval-managed Linear admin OAuth app. You'll be asked to grant admin access to your workspace." Approve the request on Linear's consent screen as a workspace admin. Serval is granted read, write, and admin access. Serval records your Linear organization's ID and name as the connected instance. The connection is workspace-wide. If this option is hidden, Serval-managed sign-in is not enabled for your deployment (self-hosted deployments hide it). If it is shown but the managed credentials are missing on the server, the connect dialog shows "Failed to initiate Linear Admin OAuth:" followed by "Linear Admin Serval-managed OAuth is not configured in this environment; connect a custom Linear OAuth app instead". Select **Use your own Linear OAuth app**: "Connect with an admin-capable Linear OAuth application owned by your workspace." Under **1. Set up your Linear OAuth app**, use the **Copy** button (it toggles to **Copied**) next to the read-only **Callback URL** field, and paste the value verbatim into your Linear application's Callback URLs list. Under **2. Enter your app's credentials**, fill in: * **Display name** (optional) - a friendly name shown in Serval, for example "My Company Linear Admin". * **Client ID** (required) - found on the application's settings page in Linear, under OAuth. * **Client secret** (required) - password field; Linear only shows this once when the app is created. The **Connect** button stays disabled until both Client ID and Client secret are filled in. If a blank value reaches the server anyway, the request is rejected and the dialog shows "Failed to initiate custom Linear admin app:" followed by "clientId is required" or "clientSecret is required". Click **Connect** and approve the request in Linear as a workspace admin. Complete the authorization within **10 minutes** - after that, the attempt fails with "Invalid or expired OAuth state" and you must submit the form again. On reconnect, Serval opens directly on this form and prefills **Display name** and **Client ID**, but **Client secret** always starts blank and must be re-entered. Submitting re-runs the full Linear authorization. ## Verifying the connection Linear Admin ships three health checks that exercise the connection end to end: **Test Linear Admin Connection** - verifies the connection works and the OAuth token is valid by reading a single user. * Success: "Successfully authenticated with Linear (found \[number] user)" * Failure: "Unable to authenticate with Linear. Please verify the Linear Admin connection is still active and the OAuth token has not been revoked." **Verify Linear Admin Access** - confirms admin access was actually granted by reading organization invites, the same capability user provisioning relies on. Unlike a plain read, this fails if the admin permission is missing. * Success: "Successfully verified Linear admin access (read organization invites)" * Failure: "Unable to read Linear organization invites. The connected Linear app may be missing the admin scope - reconnect and ensure a workspace admin grants admin access." **List Linear Users (incl. suspended)** - checks that Serval can list users including suspended ones, which is required to resolve a user before suspending them during deprovisioning. * Success: "Successfully listed Linear users including suspended (sample size: \[number])" * Failure: "Unable to list users from Linear. Please verify the Linear Admin connection has not been disconnected." If "Test Linear Admin Connection" passes but "Verify Linear Admin Access" fails, the connection authenticated fine but was never granted admin access - usually because a non-admin authorized it. Reconnect and have a Linear workspace admin approve the consent screen. ## Gotchas and troubleshooting The ticket-sync Linear integration only requests read and write access, because the connection mode that attributes issues and comments to the original requester is incompatible with Linear's admin permission. Linear Admin is the companion connection that carries admin access and owns user provisioning. Connect **Linear** for ticket syncing and issue workflows; connect **Linear Admin** for inviting, suspending, and unsuspending users. Whoever clicks through Linear's consent screen must be a workspace admin, or admin access is not actually granted. The connect dialog states this for the bring-your-own path: "The app must be authorized by a workspace admin so it can be granted admin access." If a non-admin authorizes, plain authentication succeeds but the "Verify Linear Admin Access" health check fails with the missing-admin-scope message. Linear rejects the connection if the Callback URL registered on your application differs at all from the one Serval uses. Always use the **Copy** button in Serval's connect dialog and paste the value verbatim into Linear - a retyped or partial URL fails. After you click Connect with your own app's credentials, Serval holds them for 10 minutes while you authorize in Linear. If you take longer, the attempt fails with "Invalid or expired OAuth state" and you must submit the form again. When reconnecting a bring-your-own connection, Display name and Client ID are prefilled, but the Client secret field is always blank and required - there is no leave-blank-to-keep-existing behavior. Submitting re-runs the full Linear authorization. If Serval-managed sign-in is not enabled for your deployment, the "Sign in with Linear (Admin OAuth)" option is hidden; self-hosted deployments always use their own Linear OAuth app. If the option is shown but the managed credentials are not configured on the server, the attempt fails with: "Linear Admin Serval-managed OAuth is not configured in this environment; connect a custom Linear OAuth app instead." Provisioning sends a Linear organization invitation email - the user must accept it to join the workspace; nothing is created directly. Role names are strictly mapped: "Admin" grants Linear's admin role, "Member" or "User" grants the standard member role, and any other role name fails the workflow with: Invalid role '\[name]'. Must be one of: Admin, Member, or User. Deprovisioning suspends the account (found by email, including already-suspended users) rather than deleting it; the built-in unsuspend workflow can reactivate it. Linear displays the OAuth client secret only at creation time. If it is lost, regenerate it on the application's settings page - and note that the old secret stops working for any connection still using it. After authorization, Serval records your Linear organization's ID and name as the connected instance. The connection is workspace-wide, not per-team. Tokens normally refresh automatically. If a bring-your-own token has expired and no refresh token is available, calls fail with "custom Linear admin app access token expired and no refresh token available; reconnect required" - reconnect the integration to fix it. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Linear Admin integration. # LinkedIn Source: https://docs.serval.com/sections/integrations/linkedin Connect your own LinkedIn OAuth app to Serval to read member profiles, manage Company Pages, publish posts, pull ads analytics, and manage Matched Audiences from workflows. ## About LinkedIn LinkedIn is a professional network with REST APIs covering member profiles, organization (Company) pages, advertising, and Matched Audiences. Serval connects through a bring-your-own-app model: your team registers its own app in the [LinkedIn Developer portal](https://www.linkedin.com/developers/apps) and supplies that app's Client ID and Primary Client Secret in Serval's Connect modal. Because Serval does not own a shared LinkedIn app, your team controls exactly which LinkedIn products, permissions, and rate-limit budget the connection uses. Workflow requests go only to LinkedIn's official API host (api.linkedin.com). **Authentication:** Bring-your-own LinkedIn app using the [OAuth 2.0 authorization code flow](https://learn.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow). You pick which permissions to request, register Serval's redirect URL on your app, and enter your Client ID and Primary Client Secret. **Data sync:** On demand only - there is no background sync. Workflows call the LinkedIn REST API at run time, and Serval injects and automatically refreshes the access token for you (LinkedIn access tokens last about 60 days by default; refresh tokens, where available, about 365 days). ## What the LinkedIn integration enables | Capability | Description | | - | - | | Read member profile | Fetch the connected member's basic profile (name, headline, vanity name, profile picture). Works on every connection because the Sign In with LinkedIn permission is always included. | | Check 1st-degree connection count | Look up the connected member's total number of 1st-degree connections. Requires the Connection insights permission plus enrollment in LinkedIn's Marketing Developer Platform program. | | List administered organizations | List the organizations (Company Pages) the connected member has a role on, filterable by role and approval state. Requires a [Community Management API](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/community-management-overview) permission. | | Discover ad accounts | Find the ad accounts the connected member can act on, including the account identifiers used by other advertising calls. Requires an [Advertising API](https://learn.microsoft.com/en-us/linkedin/marketing/) permission. | | Fetch ads analytics | Pull advertising analytics across accounts, campaigns, or creatives, with daily, monthly, yearly, or all-time granularity. Requires the Advertising API reporting permission. | | Publish posts | Create posts as the member or as an organization, with control over visibility, draft versus published state, and resharing. Requires Share on LinkedIn for member posts or Community Management API for organization posts. | | Manage Matched Audiences | Create, read, update, and delete Matched Audience (DMP) segments used for ad targeting. Requires the Matched Audiences permission. | Anything defined in the [LinkedIn API](https://learn.microsoft.com/en-us/linkedin/) can be accessed through Serval. ## Get your credentials You need your own LinkedIn OAuth app with the right products approved, its scopes enabled, and Serval's redirect URL registered. Everything happens in the [LinkedIn Developer portal](https://www.linkedin.com/developers/apps). Go to the [LinkedIn Developer portal](https://www.linkedin.com/developers/apps) and click **Create app**, or open an existing app. Associate a LinkedIn Company Page - LinkedIn gates many products on the app being linked to a verified Company Page. On the **Products** tab, click **Request access** next to the products matching the permissions you will select in Serval (Share on LinkedIn, Advertising API, Community Management API, and so on). LinkedIn must approve each product before its permissions work - some are auto-approved, others are reviewed and can take days. Connect Serval only after the products show under **Added products**. On the **Auth** tab, under **OAuth 2.0 scopes**, approve the scopes for the products you added. You will pick the matching subset in Serval's Connect modal - Serval only requests what you select. Still on the **Auth** tab, under **Authorized redirect URLs for your app**, paste the exact Redirect URL shown in Serval's Connect modal and click **Update**. The URL is environment specific - always use the value from the modal, never a hand-constructed one. From the **Auth** tab, copy the **Client ID** and the **Primary Client Secret** into Serval's Connect modal. Do not click **Generate a new Client Secret** on LinkedIn after connecting. LinkedIn invalidates the previous secret immediately, which breaks Serval's automatic token refresh until you reconnect with the fresh secret. LinkedIn uses a two-layer permission model: products (Products tab) grant the right to use scopes (Auth tab). A scope can be approved and still fail until the backing product appears under **Added products**. ## Connect in Serval The Connect modal has two steps: **Permissions**, then **Connect**. Check the permission bundles that match the products your LinkedIn app has. **Sign In with LinkedIn** is shown checked and disabled with the tag "Always included" - it is requested on every connection. The bundles are convenience groupings, not a strict one-to-one product map (some scopes are granted by more than one LinkedIn product), so you can also expand **All permissions** and search individual scopes (search placeholder: "Search all LinkedIn permissions...") to add a single scope without taking a whole bundle. Serval requests only what you select; an unrecognized scope is rejected with "unsupported LinkedIn scope: \[scope]". | Permission bundle | LinkedIn scopes requested | | - | - | | Sign In with LinkedIn (always included) | `r_basicprofile` | | Share on LinkedIn | `w_member_social` | | Advertising API | `r_ads`, `rw_ads`, `r_ads_reporting` | | Community Management API | `r_organization_admin`, `rw_organization_admin`, `r_organization_social`, `w_organization_social` | | Matched Audiences | `rw_dmp_segments` | | Connection insights | `r_1st_connections_size` | Only select permissions your LinkedIn app actually has enabled. Requesting even one scope the app lacks fails the entire authorization with LinkedIn's `unauthorized_scope_error`. The modal displays a read-only **Redirect URL** with a **Copy** button (it toggles to "Copied"). Helper text: "Add this as an Authorized redirect URL in your LinkedIn app's Auth tab." Register it on your LinkedIn app before continuing. All three fields are required: the **Connect to LinkedIn** button stays disabled until every field is filled, the form refuses to submit without them ("Please fill in all required fields"), and blank values are also rejected server-side ("appName is required", "clientId is required", "clientSecret is required"). * **Connection name** (required) - a Serval-side label only. Helper text: "The name that will identify this connection in Serval. We recommend using your LinkedIn app name." LinkedIn does not expose your app's display name to Serval, so you choose it. * **Client ID** (required) - from your LinkedIn app's Auth tab. * **Primary Client Secret** (required, hidden password field) - from your LinkedIn app's Auth tab. Click **Connect to LinkedIn** and approve the consent screen. Complete it within 10 minutes - Serval holds your pending credentials only that long, after which you will see "Invalid or expired OAuth state" or "OAuth session expired, please try again" and need to restart the flow. There is no separate edit-credentials form. To update the secret or pick up newly approved permissions, run the Connect flow again with the same Client ID - the existing connection is updated in place (the connection is keyed on the Client ID), your workflows are preserved, and the permission picker is pre-seeded with the scopes the connection currently has so you do not accidentally downgrade. A different Client ID creates a separate connection. ## Verifying the connection The LinkedIn integration ships three health checks: * **Test LinkedIn Connection** - verifies Serval can authenticate by fetching the connected member's basic profile. * Success: "Successfully connected to LinkedIn as \[name]" * Failure: "Unable to connect to LinkedIn. Verify your OAuth credentials are valid, the app has the r\_basicprofile scope approved, and the token has not been revoked." * **Get 1st-degree Connection Count** - verifies the Connection insights permission by fetching the member's total 1st-degree connections. * Success: "Authenticated member has \[number] 1st-degree connection(s)." or, when LinkedIn omits the count, "API access verified but LinkedIn did not return a connection count. The scope is approved but the member may not have any connections exposed." * Product-gating failure: "Your LinkedIn app has the r\_1st\_connections\_size scope approved, but the /v2/connections endpoint requires the app to also be enrolled in the LinkedIn Marketing Developer Platform program. Apply for the program from your LinkedIn app's Products tab - once approved, this check will pass without needing to reconnect." * Generic failure: "Unable to fetch connection count. Verify your LinkedIn app has the r\_1st\_connections\_size scope approved on the Auth tab." * **List Administered Organizations** - verifies the organization-admin permission by listing organizations the member administers. * Success: "Found \[number] administered organization(s)." or, with zero results, "API access verified but this member does not administer any organizations." * Failure: "Unable to list organizations. Verify your LinkedIn app has the r\_organization\_admin or rw\_organization\_admin scope approved." A green **Test LinkedIn Connection** with failures elsewhere almost always means product gating: basic profile access works on every live connection, but other calls fail until the backing LinkedIn product is approved under **Added products**. Once LinkedIn approves the product, the failing checks pass without reconnecting. ## Gotchas and troubleshooting LinkedIn products gate scopes. A scope checked on the Auth tab appears on the consent screen and in the granted list, yet calls return 403 until the backing product is under **Added products** on the Products tab. The clearest example: the connection-count check fails with LinkedIn's ACCESS\_DENIED error when the Connection insights scope is approved but the app is not enrolled in the Marketing Developer Platform program. Apply for the missing product from the Products tab - once approved, calls succeed without reconnecting. You selected a permission in step 1 that your LinkedIn app does not have enabled. LinkedIn fails the entire authorization, not just the one scope. Restart the Connect flow and select only the bundles matching the products your app actually has, or enable the missing scope on the app's Auth tab first. Serval holds the credentials you submit in the Connect modal for only 10 minutes between clicking **Connect to LinkedIn** and finishing LinkedIn's consent screen. Taking longer shows "Invalid or expired OAuth state" or "OAuth session expired, please try again". Just restart the Connect flow. The Client ID or Primary Client Secret does not match a live LinkedIn app credential. Re-copy both values from your app's Auth tab - and if someone clicked **Generate a new Client Secret**, the old secret is already invalid and you must reconnect with the new one. Serval refreshes access tokens using the Client ID and secret stored with the connection. Generating a new Client Secret on LinkedIn invalidates the previous one immediately, so refresh fails until you reconnect with the fresh secret. Reconnecting with the same Client ID updates the existing connection in place. Note that refresh tokens only exist when your app is enrolled in LinkedIn's refresh token program; otherwise reconnect when the access token expires (about 60 days). LinkedIn grants the Advertising API at a Development tier first, with tighter limits on accessible ad accounts and request volume. If advertising calls work in testing but hit limits in production, apply for the Standard tier from your app's Products tab on LinkedIn. This is LinkedIn-side behavior and approval is at LinkedIn's discretion. LinkedIn retired its legacy ad-account discovery calls, which now return errors. Use the integration's ad-account discovery capability instead, which runs on LinkedIn's current versioned Marketing API. Serval automatically attaches the protocol and version headers LinkedIn's versioned API requires, so you never set them yourself. When a workflow creates a Matched Audience segment, LinkedIn returns the new segment's ID in a response header rather than the response body, and update or delete operations return an empty success response. Only the segment's name, description, access policy, and source segment can be updated. Populating a segment with members uses LinkedIn's separate CSV list-upload process, which is not available through this integration's API action. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your LinkedIn integration. # Linx Security Source: https://docs.serval.com/sections/integrations/linx Connect Linx Security, an identity governance (IGA) platform, so workflows can read identities, accounts, and applications, and create access requests, through the Linx API - authenticated with OAuth client credentials. The Linx Security integration is in beta. ## About Linx Security Linx Security is an identity governance and administration (IGA) platform. Serval connects to your Linx tenant with an API client so workflows can read human and non-human identities, accounts, applications, groups, roles, and workflows, create access requests, and reach the rest of the Linx API on demand. **Authentication:** OAuth 2.0 client credentials (a Client ID and Client Secret). Serval exchanges them for a short-lived access token at `https://connect.linxsecurity.io/api/authorize` and refreshes it automatically before it expires, so there is no browser redirect and no per-user sign-in. **Data sync:** On demand only. There is no background sync and no entity ingestion. Workflows call the Linx API live at `connect.linxsecurity.io` when they run. ## Get your credentials Contact **Linx Support** to obtain an API Client ID and Client Secret for your tenant. There is no self-serve credential page. ## Connect in Serval In Serval, open the Linx Security integration and start a new connection. Paste the Client ID provided by Linx Support. Paste the matching Client Secret (a password field). Submit the form. Serval runs the health checks below to confirm the credentials work. ## Verifying the connection The Linx Security integration ships three health checks, each a lightweight read of a single record: * **List workflows**, confirming access to the Administrative API. * **List humans**, confirming access to identity data. * **List applications**, confirming access to application data. A passing set confirms Serval can mint a token and read from your Linx tenant. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Linx Security integration. # Lumos Source: https://docs.serval.com/sections/integrations/lumos Lumos is an identity governance and app management platform; Serval connects to it with a Lumos API token to read users, apps, accounts, groups, and AppStore data, and to submit access requests and act on Lumos approval tasks from your workflows. ## About Lumos Lumos is an identity governance and app management platform. The Serval Lumos integration connects to the Lumos REST API to read your organization's directory and app data: users, apps, accounts, and groups, plus the Lumos AppStore, including each app's request-flow approvers and requestable permissions. It also writes to the AppStore request flow: Serval can submit an access request on a user's behalf and act on the Lumos approval tasks that result, so a requester and an approver can both stay in Serval. Lumos remains the system of record - it evaluates the request against its own policy, records the approval decision, and provisions the access. Serval does not run the approval workflow, it surfaces and acts on Lumos tasks. Serval stores your API token encrypted and attaches it to every request automatically, so workflow code never sees the raw token. Serval only ever sends the token to one host for this integration: api.lumos.com. **Authentication:** API token (bearer). You paste a Lumos API token (starts with lsk\_) into Serval's connect form; there is no OAuth flow. **Data sync:** On demand only. There is no background sync - Lumos data is fetched live whenever a workflow runs, so app and permission lookups always reflect the current AppStore rather than a cached copy. ## What the Lumos integration enables | Capability | Description | | - | - | | Search Lumos Requestable Permissions | Search requestable permissions across the whole AppStore, or within one app, by group name, request configuration name, or integration-specific ID. Returns each match with its manager-approval setting and the stage-1 and stage-2 approvers it will route to. Part of the Access Requests bundle. | | Create Lumos Access Request | Submit an AppStore access request for an app and optionally specific permissions, on behalf of a target user, with a business justification and an optional access duration. Lumos then runs its own approval and provisioning. Part of the Access Requests bundle. | | List Lumos Access Requests | Page through access requests filtered by target user, requester, or status, optionally including each request's approval tasks so you can tell who a request is waiting on. Part of the Access Requests bundle. | | Get Lumos Access Request | Fetch a single access request by ID with its approval tasks, status notes, and requested permissions, so a requester gets a status answer in Serval instead of a link back to Lumos. Part of the Access Requests bundle. | | Cancel Lumos Access Request | Cancel a pending access request by ID, recording an optional cancellation reason. Part of the Access Requests bundle. | | List Lumos Approval Tasks | Page through Lumos AppStore tasks - pending approvals by default - optionally narrowed to one assignee or one access request. Returns each task's assignees so it can be routed to the right Serval user. Part of the Approvals bundle. | | Get Lumos Task | Fetch a single task by ID along with the actions it currently offers. Part of the Approvals bundle. | | Approve Lumos Task | Approve a pending approval task, optionally recording the approver's reasoning as a comment in Lumos first. Part of the Approvals bundle. | | Deny Lumos Task | Deny a pending approval task, optionally recording the denial reason as a comment in Lumos first. Part of the Approvals bundle. | | Reassign Lumos Task | Reassign a task to other users and/or groups, either replacing the current assignees or adding to them. Part of the Approvals bundle. | | Comment on Lumos Task | Add a comment to a task so a clarifying question or an approval rationale reaches the Lumos audit trail rather than living only in the Serval ticket. Part of the Approvals bundle. | | List Lumos AppStore Apps | Page through all apps available in the Lumos AppStore, optionally filtered by a name search. Returns each app's ID, label, status, and category. Part of the AppStore bundle. | | Get Lumos App Approvers | Fetch the AppStore request-flow settings for a Lumos app by ID, returning its stage-1 approvers, stage-2 approvers, admins, and whether manager or additional approval is required. Part of the AppStore bundle. | | List Lumos App Requestable Permissions | Page through the requestable permissions for a Lumos AppStore app by ID. Returns each permission's label, type, AppStore visibility, manager-approval setting, and its stage-1 and stage-2 approvers. Part of the AppStore bundle. | | List Lumos Accounts | Page through accounts in Lumos, optionally filtered by app ID or account lifecycle status (for example ACTIVE, SUSPENDED, or DEACTIVATED). Returns each account's ID, app, email, name, and status. Part of the Directory & Apps bundle. | | List Lumos Users | Page through users in the Lumos organization, optionally filtered by a search against name and email. Returns each user's ID, email, name, and status. Part of the Directory & Apps bundle. | | List Lumos Groups | Page through groups in Lumos, optionally filtered by group name or app ID. Returns each group's ID, name, sourcing app, description, and integration-specific ID. Part of the Directory & Apps bundle. | | List Lumos Apps | Page through all apps Lumos knows about for the organization, optionally filtered by a name search. Returns each app's ID, label, status, category, and app class ID. Part of the Directory & Apps bundle. | | Get Lumos App | Fetch a single Lumos app by its ID, returning its full details. Part of the Directory & Apps bundle. | | Lumos API request | Typed action for custom workflows covering every endpoint Serval models: the current user, users, apps, accounts, groups, AppStore apps, per-app request-flow settings, requestable permissions, access requests, and tasks. | These workflows, along with the typed Lumos API request action, cover the endpoints Serval models from the [Lumos API](https://developers.lumos.com/reference/lumos-api). You can install the prebuilt workflows from Workflows, then Installable in Serval, or build your own in [Catalyst](/sections/documentation/catalyst/overview). The four bundles are meant to be installed in layers. **Access Requests** and **Approvals** together give you the end-to-end flow - resolve the app and permission, submit the request, then surface and resolve the resulting approval task. **AppStore** and **Directory & Apps** are read-only lookups you can install on their own if you only want Serval to answer questions about Lumos. A typical end-to-end request looks like this: Run **List Lumos AppStore Apps** to find the app, then **Search Lumos Requestable Permissions** to find the specific permission. Both query Lumos live, so a newly added app or permission is immediately requestable. Collect the target user, the business justification, and the access duration before submitting. Lumos shows the justification to approvers. Run **Create Lumos Access Request**. Lumos returns one access request per requested permission, and then evaluates its own approval policy. Run **List Lumos Approval Tasks** to find pending tasks and route each one to its assignee in Serval. Run **Approve Lumos Task** or **Deny Lumos Task**, with a comment to record the reasoning in Lumos. Lumos records the decision and provisions the access. Run **Get Lumos Access Request** to tell the requester where things stand without sending them to Lumos. ## Get your credentials You need an active Lumos organization and a Lumos API token, which starts with lsk\_. Tokens inherit and retain the permissions of the user who creates them, so create the token from an admin or service account whose permissions cover the data your workflows need (admin access is required to create API tokens in Lumos). Lumos walks through token creation in its [API Quick Start guide](https://developers.lumos.com/docs/quick-start); the [REST API guide](https://developers.lumos.com/docs/rest-api) has more background. Sign in to Lumos and go to Settings, then API Tokens, at the [Lumos API Tokens settings page](https://app.lumosidentity.com/settings/api_tokens). Click "Add API Token", enter a name and a description, then click "Create API Token." Copy the token that starts with lsk\_. Lumos only shows the API token at creation time, so store it securely before closing the dialog. Paste the token into the API Token field in Serval's Lumos connect form (next section). Lumos shows the token only once, at creation. If you lose it, you cannot view it again - you must create a new token. Because tokens carry their creator's permissions, prefer a service or admin account over a personal one, and plan to rotate the token if that person leaves or changes roles. ## Connect in Serval In Serval, add the Lumos integration to open its connect form. The form has a single field, **API Token** (entered like a password, hidden as you type), with the helper text: "Your Lumos API token (starts with lsk\_). Generate one from the API Tokens page in Lumos settings." Save the form. Serval does not validate the token's format at this point - a typo is accepted here and only surfaces when the automatic health check runs (see the next section). If the connection cannot be saved at all, you may see "Failed to connect service" or "Failed to install integration". When you later edit an existing connection, the saved token appears as a masked value - bullets plus its last 4 characters - that you cannot type into directly. To rotate the token, click the pencil icon (on the connection settings page) or the **Replace** button (on the reconnect form) to get an empty "Enter new value" box, then paste the complete new lsk\_ token and save. Leaving the token untouched, or saving while the replacement box is still empty, keeps your existing stored token. If an update fails, Serval shows "Failed to update integration" or "Failed to update configuration", depending on which form you used. ## Verifying the connection The Lumos integration has one health check, **Get Current Lumos User**. It uses your stored token to fetch the Lumos user who created the token, proving the integration is configured and the token is valid. It runs automatically after you connect or update the integration, and you can also trigger it from the app instance page. * On success: "Successfully connected to Lumos as \[email]." (If the token's user has no email, it reads "Successfully connected to Lumos.") * On failure: "Unable to fetch the current Lumos user. Please verify your API token is valid." A passing health check proves the token works, not that it can see everything. Tokens carry the permissions of the user who created them, so if the check is green but a workflow comes back with missing or empty Lumos data, check whether the token's creator has access to that data in Lumos. ## Gotchas and troubleshooting The token (lsk\_...) is displayed only at creation time on the Lumos API Tokens page. Copy it before closing the dialog; if it is lost you must create a new token and update the Serval connection with it. Lumos API tokens inherit and retain the permissions of the user who created them. Create the token from a service or admin account whose permissions match what your workflows need, and rotate the token if that person leaves or changes roles. The API Token field has no format check, and the lsk\_ prefix is not enforced. A typo or truncated paste is accepted at connect time and only surfaces when the "Get Current Lumos User" health check fails with: "Unable to fetch the current Lumos user. Please verify your API token is valid." If you see that message right after connecting, re-copy the token from Lumos and replace it in Serval. Lumos authorizes task actions against the user who owns the API token. Completing, dismissing, or reassigning a task returns 403 unless that user is an assignee of the task or a Lumos domain admin. If approvals fail for some tasks but not others, this is usually why - use an admin token, or route each task to a Serval workflow that runs with a token that can act on it. When Serval surfaces pending Lumos approval tasks, approvers will also receive Lumos's own approval notifications unless those are disabled in Lumos. Turn off Lumos approval notifications for the apps Serval fronts, otherwise every approver gets pinged twice for the same decision. "List Lumos Approval Tasks" returns only the tasks assigned to the API token's own user by default. Enable **Show All Tasks** to see the whole domain's queue - that option requires an admin token. "Approve Lumos Task" and "Deny Lumos Task" use Lumos's complete and dismiss endpoints, which resolve a task that has a single action. A task offering several actions must be resolved through Lumos's perform-action endpoint, which Serval does not model. Run "Get Lumos Task" first to see the actions a task actually offers. Serval can create and cancel access requests and act on tasks. Other Lumos write operations - creating apps, uploading accounts, editing requestable permissions or pre-approval rules - are not available through the integration. Lists of users, apps, accounts, groups, AppStore data, access requests, and tasks are returned one page at a time, with up to 100 items per page (50 by default) and a page count included in each response. The prebuilt Serval workflows page through results for you; custom workflows need to request each page until the last one is reached. Lumos expects a separate expand parameter per field, so a custom workflow can only expand one field per call - passing several comma-joined silently returns no expansion rather than an error. This is why "Get Lumos Access Request" makes a second call when you ask it for custom fields, and why the task workflows expand either assignees or actions but not both. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Lumos integration. # ManageEngine Endpoint Central Source: https://docs.serval.com/sections/integrations/manageengine-endpoint-central Connect ManageEngine Endpoint Central Cloud to Serval so workflows can manage devices, patches, inventory, and security reports on demand. ## About ManageEngine Endpoint Central ManageEngine Endpoint Central (formerly Desktop Central) is a unified endpoint management (UEM) platform for managing computers, mobile devices, patching, and inventory. Serval connects to Endpoint Central Cloud, the Zoho-hosted edition, using a Serval-managed Zoho OAuth application - there is nothing to register or configure on the ManageEngine or Zoho side. The integration is fully region-aware: your Zoho data center (US, EU, IN, AU, JP, CN, or SA) is detected automatically when you connect. **Authentication:** Zoho OAuth 2.0 with a Serval-managed application. A click-through authorization flow - no API keys or credentials to paste. **Data sync:** On demand only. There is no background sync or scheduled ingestion; workflows call Endpoint Central at run time through a single API request action. ## What the ManageEngine Endpoint Central integration enables | Capability | Description | | - | - | | API request action | A single typed action, "ManageEngine Endpoint Central API request", covering 112 documented API operations, with automatic authentication and token refresh. | | Scope of Management | List managed computers and remote offices, view the SOM summary, install, uninstall, or remove agents, and list custom groups. | | Patch management | View patch summaries and reports, scan computers, approve, decline, or unapprove patches, install or uninstall patches, and manage automated patch deployment (APD) tasks and deployment policies. | | Inventory | Hardware and software inventory, installed software per computer, license and software metering data, prohibited software, and on-demand inventory scans. | | Vulnerability and threat data | Read vulnerabilities, threat patches, server and system misconfigurations, and per-system threat reports (read-only). | | Mobile Device Management | Module access granted by the **Mobile Device Management** permission preset: workflows can view and manage mobile device policies and enrollments through the Endpoint Central MDM module. | | Remote tools and configurations | Module access granted by the **Remote Tools** and **Configurations** permission presets: workflows can view and manage remote control sessions and tools, plus system configurations and policies. | | Security and compliance reports | BitLocker reports including recovery key details and TPM status, device control audit reports, and DLP reports. | | Custom fields and reporting | Custom columns and custom field values for computers, custom reports and query reports with data export, and endpoint analytics scores. | Anything defined in the [ManageEngine Endpoint Central API](https://www.manageengine.com/products/desktop-central/api/cloud_index.html) can be accessed through Serval. ## Get your credentials There is nothing to create in any provider console. Serval uses its own managed Zoho OAuth application, so you never register an app, generate a client ID, or copy a secret. You only need two things in place before connecting: The integration works with the cloud product only. If your team runs a self-hosted (on-premises) Endpoint Central server, it cannot be connected. See the [Endpoint Central Cloud API documentation](https://www.manageengine.com/products/desktop-central/api/cloud_index.html) for an overview of what the cloud edition exposes. Know which Zoho account is linked to your Endpoint Central instance, and make sure it has admin privileges for the modules you plan to use (patching, inventory, MDM, and so on). This is the account you will sign in with on the Zoho consent screen. Cloud only: on-premises Endpoint Central servers are not supported by this integration. Your regional Zoho data center (US, EU, IN, AU, JP, CN, or SA) is detected automatically during connection - there is no region picker and nothing to look up in advance. ## Connect in Serval In Serval, go to **Integrations > All integrations > ManageEngine Endpoint Central**. A permissions modal opens with the message: "Common read and update permissions are always included. Select any additional module permissions your workflows need. You can always reconnect later to change permissions." Under **Permission Presets** ("Select the permissions you need for your workflows"), check any of the seven optional presets. There are no text inputs - these checkboxes are the only choices, and base read and update permissions are always included automatically. | Preset | What it grants | | - | - | | Scope of Management | "View and manage computer groups and managed devices" - `DesktopCentralCloud.SOM.READ`, `DesktopCentralCloud.SOM.UPDATE` | | Patch Management | "View and manage patches, updates, and vulnerability scans" - `DesktopCentralCloud.PatchMgmt.READ`, `DesktopCentralCloud.PatchMgmt.UPDATE` | | Inventory | "View and manage hardware and software inventory" - `DesktopCentralCloud.Inventory.READ`, `DesktopCentralCloud.Inventory.UPDATE` | | Vulnerability Management | "View vulnerability assessment and management data" - `DesktopCentralCloud.VulnerabilityMgmt.READ` (read-only) | | Mobile Device Management | "View and manage mobile device policies and enrollments" - `MDMOnDemand.MDMDeviceMgmt.READ`, `MDMOnDemand.MDMDeviceMgmt.UPDATE` | | Remote Tools | "View and manage remote control sessions and tools" - `DesktopCentralCloud.Tools.READ`, `DesktopCentralCloud.Tools.UPDATE` | | Configurations | "View and manage system configurations and policies" - `DesktopCentralCloud.Configurations.READ`, `DesktopCentralCloud.Configurations.UPDATE` | Expand any preset row to see the exact permission strings it grants, each with a short description. A live counter shows "\[number] additional permissions selected" as you check boxes - it counts individual permissions, not presets (most presets add two). Click **Connect to Endpoint Central** (the button reads "Connecting..." while the authorization starts). Authorization opens in a popup window or a full-page redirect. If Serval cannot start the authorization, you will see "Failed to initiate OAuth: \[status text]" or "OAuth initiation failed" - retry, and contact support if it persists. Sign in with the Zoho account linked to your Endpoint Central instance and approve the requested permissions. The consent screen appears on every connect and reconnect - this is expected. Serval detects your Zoho data center from the authorization response and stores it with the connection. All API calls and token refreshes use your regional servers from then on. Base read and update permissions (`DesktopCentralCloud.Common.READ` and `DesktopCentralCloud.Common.UPDATE`) are always requested, even if you select no presets. Selecting no presets still produces a working connection for basic operations. Permissions are fixed at connect time. If your workflows later need a module you did not select, reconnect the integration and check the additional presets. ## Verifying the connection After connecting, Serval runs two health checks: **Test ManageEngine Endpoint Central Connection** verifies that Serval can authenticate against your regional Endpoint Central Cloud instance using the always-included base permissions. * Success: "Successfully authenticated with ManageEngine Endpoint Central" * Failure (invalid or expired token): "Unable to authenticate with ManageEngine Endpoint Central. The OAuth token is invalid or expired - please reconnect the integration." * Failure (other): "Unable to reach ManageEngine Endpoint Central. Please verify the integration's regional data center and OAuth credentials are valid." **List ManageEngine Managed Computers** verifies that Serval can list managed computers through the Scope of Management module, fetching a sample of at most one computer. * Success: "Successfully listed managed computers from ManageEngine Endpoint Central (sample size: \[number])" - the number is 0 or 1 depending on how many computers your instance returned * Failure: "Unable to list managed computers from ManageEngine Endpoint Central. Please verify the integration has the necessary permissions." If **Test ManageEngine Endpoint Central Connection** passes but **List ManageEngine Managed Computers** fails, the most likely cause is a missing permission: reconnect and select the **Scope of Management** preset. ## Gotchas and troubleshooting Permissions are baked into the OAuth grant when you connect - they cannot be edited in place. If a workflow hits a 403 or insufficient-scope error, reconnect the integration and select the additional presets the workflow needs. The connect modal reminds you: "You can always reconnect later to change permissions." If health checks report an invalid or expired token, reconnect the integration. Make sure you sign in with the Zoho account that is actually linked to your Endpoint Central instance and that it still has admin privileges for the modules you authorized. Token refresh is automatic; a persistent failure usually means the grant was revoked on the Zoho side and a fresh connect is required. The integration only reaches Endpoint Central Cloud regional domains (endpointcentral.manageengine.com and its eu, in, com.au, jp, com.cn, and sa counterparts). Self-hosted Endpoint Central servers cannot be connected. Your regional data center is detected and stored when you connect. Connections created before regional support default to the US region; if your organization is hosted in the EU, IN, AU, JP, CN, or SA data center and you see "Unable to reach ManageEngine Endpoint Central" failures on an older connection, reconnect so the correct region is captured. This is by design. Serval always requests the full consent flow because Zoho only reliably issues refresh tokens that way. Seeing the complete consent screen on every reconnect is normal, not a sign of a broken session. The Vulnerability Management preset grants read access only. Workflows can read vulnerability, threat, and misconfiguration data but cannot make changes through this preset. Endpoint Central expects a Zoho-specific authorization scheme rather than the standard Bearer scheme. Serval injects the correct header automatically on every request, so no action is needed - this only matters if you are comparing behavior against raw examples from the ManageEngine API documentation. For more detail, see the [Endpoint Central Cloud API documentation](https://www.manageengine.com/products/desktop-central/api/cloud_index.html), the [Endpoint Central API documentation index](https://www.manageengine.com/products/desktop-central/api/), the [Zoho OAuth 2.0 overview](https://www.zoho.com/accounts/protocol/oauth.html), and [Zoho multi-data-center OAuth](https://www.zoho.com/accounts/protocol/oauth/multi-dc.html). *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your ManageEngine Endpoint Central integration. # ManageEngine Endpoint Central (On-Premises) Source: https://docs.serval.com/sections/integrations/manageengine-endpoint-central-onprem Connect Serval to your self-hosted ManageEngine Endpoint Central server so workflows can look up managed computers, read inventory and patch status, and, when you allow it, deploy patches. ## About ManageEngine Endpoint Central (On-Premises) ManageEngine Endpoint Central (formerly Desktop Central) manages Windows, macOS, and Linux endpoints: it inventories hardware and software, scans for missing patches and vulnerabilities, and deploys patches and software. This integration connects Serval to an Endpoint Central server you host yourself. If you use Endpoint Central Cloud, use the [ManageEngine Endpoint Central](/sections/integrations/manageengine-endpoint-central) integration instead; the two share the same API but authenticate differently. The integration is marked **Beta** in the connect screen, so its capabilities may still change. **Authentication:** An Endpoint Central authentication key for a dedicated console user. Serval sends it to your server on each request, and workflows never handle it. **Access level:** You choose what Serval may do when you connect, and Serval enforces it server-side on every request: * **Read-only** reads computers, inventory, patches, vulnerabilities, custom fields, and reports. * **Full** adds approving and deploying patches, scanning computers, managing agents, and editing custom fields. The key's Endpoint Central role applies on top of the access level: Serval can never do more than that user can. **Data sync:** None. Serval calls your server only when a workflow or health check runs. ## What the Endpoint Central (On-Premises) integration enables | Capability | Description | | - | - | | Endpoint Central API request | A generic workflow action that can call the Endpoint Central REST API (`/api/1.4` and `/dcapi` paths): Scope of Management computers and agents, inventory (hardware, software, licenses, prohibited software), patch management (patches, systems, approval, deployment, and automated patch deployment tasks), vulnerabilities and misconfigurations, BitLocker reports, custom groups, custom fields, and query reports. | The read-only access level is enforced by Serval, not just documented: with it selected, Serval refuses any request to your server that isn't a read, so workflows can't deploy patches, change agents, or edit custom fields. ## Before you connect Most Endpoint Central servers sit on an internal network that Serval's cloud can't reach. Three deployments are possible: * **Server reachable from the internet**: connect normally, nothing extra needed. * **Self-hosted Serval deployment**: works when your deployment is configured to allow internal targets. * **Serval cloud with a self-hosted worker**: Enable **Run on self-hosted workers** for the connection. Requests then run from your network; the worker must be able to reach the server on its HTTPS port (8383 by default). A read-only connection also needs an up-to-date worker: on an older worker every request fails with a message asking you to upgrade it, because the older worker cannot enforce the read-only boundary per request. Serval always connects over HTTPS and verifies the server's certificate. Endpoint Central installs with a self-signed certificate, which fails verification. Either replace it with a certificate from a CA Serval trusts, or, when connecting through a self-hosted worker, pass your internal CA chain to the worker with `--ca-certificate` when you install or upgrade it. Serval never skips certificate verification. ## Get your credentials In the Endpoint Central console, go to **Admin**, then **User Administration**, and create a user such as `svc-serval`. Give it a role that grants only the modules your workflows need, for example read access to Scope of Management, Inventory, and Patch Management. For a Full connection, add write access to the modules workflows will change. Make sure the role allows API access. Sign in as that user, go to **Admin**, then **Integrations**, then **API Explorer**, and open **Authentication**. Choose **Local Authentication** or **AD Authentication** to match the account, enter its credentials, and run the login. If two-factor authentication is enabled, complete the one-time-password step. Copy the `auth_token` value from the response; this is the authentication key. Use the hostname or IP address you use to open the Endpoint Central console, without the "https\://" prefix, for example `endpointcentral.example.com`. The server listens on port 8383 for HTTPS unless your installation changed it. ## Connect in Serval In Serval, go to the integrations page and select **ManageEngine Endpoint Central (On-Premises)** (marked Beta). Enter the hostname or IP address of your server, for example `endpointcentral.example.com`. Port 8383 is assumed; add a port only if your server uses a different one. Paste the key from the previous section. It's stored encrypted and shown masked after saving. Select **Read-only** unless workflows need to deploy patches, manage agents, or edit custom fields. You can change it later in the integration settings. Saving validates the format of what you entered but doesn't call your server, because the connect screen can't reach an internal network even when workflows can. Run the health checks afterward to confirm the key works. ## Verifying the connection | Health check | What it proves | | - | - | | Test Endpoint Central Connection | The server is reachable and the authentication key is accepted. | | List Endpoint Central Managed Computers | The user's role can read Scope of Management. | | List Endpoint Central Inventory Computers | The user's role can read Inventory. | | Read Endpoint Central Patch Summary | The user's role can read Patch Management. | If the connection test passes but a module check fails, the key is valid and the user's role lacks that module. ## Gotchas and troubleshooting The authentication key belongs to the user that generated it. Deleting or disabling that user, or generating a new key for it, invalidates the stored key and requests fail with an authentication error. Generate a new key and update it in the integration settings. Endpoint Central returns only the computers and data the key's user can see. When a workflow can't find a computer you know is managed, check the user's role and scope before suspecting the connection. Enter a hostname or an IPv4 address for the server. IPv6 addresses are rejected when you save the connection, because the self-hosted worker's network rules support IPv4 only. Endpoint Central MSP uses a different API version and isn't covered by this integration. With the Full access level, a workflow can approve and install patches, which can reboot the targeted computers depending on the deployment policy. Scope such workflows to explicit resource IDs, and test them against a small custom group first. The connect tile is marked Beta, so the available actions may still change. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your ManageEngine Endpoint Central integration. # Medallia Agent Connect Source: https://docs.serval.com/sections/integrations/medallia Connect Medallia Agent Connect (formerly Stella Connect) so Serval workflows can call its API on demand, with all credentials handled securely by Serval. ## About Medallia Agent Connect [Medallia Agent Connect](https://www.medallia.com/solution/agent-connect/) (formerly Stella Connect) is a real-time customer feedback and coaching platform for contact center agents. The Serval integration lets workflows call any Agent Connect API on demand - sending survey invites, managing users, or pulling feedback data - while Serval handles authentication behind the scenes. Agent Connect requires a freshly signed access token on every single request, and Serval creates one automatically each time; your workflows never see or handle the API key or secret. **Authentication:** API Key + API Secret (Serval signs a fresh token on every request) **Data sync:** On-demand only - no background sync, polling, or webhooks; nothing is mirrored into Serval ## What the Medallia Agent Connect integration enables | Capability | Description | | - | - | | Medallia Agent Connect API request action | A flexible workflow action that can call any endpoint on your Agent Connect API host. It covers all Agent Connect API families - Requests and Feedback (for example, sending a survey invite), User Management, and Data Return. | | Per-request token signing | Serval signs a fresh token with your stored API secret on every outbound request and attaches both headers Agent Connect requires. Workflow authors get full API access without ever handling credentials. | | Connection health check | The "Test Medallia Agent Connect Connection" health check verifies end to end that your API key, API secret, and API host work together. | Anything defined in the [Medallia Agent Connect API](https://docs.medallia.com/en/agent-connect/api) can be accessed through Serval. ## Get your credentials No app registration is needed. You need the API key and API secret that Agent Connect issues for your tenant, plus your tenant's API gateway host. Medallia's [authentication reference](https://docs.medallia.com/en/agent-connect/api/authentication) covers the underlying details. Admin access is required to view the Integrations page. The page lists your tenant's test and production API keys, each with a corresponding API secret. Choose the pair for the environment this connection will target - test or production. Your host is `yoursubdomain.api.stellaconnect.net`, where the subdomain matches your Agent Connect account. If you sign in at `yoursubdomain.stellaconnect.net`, your API host is `yoursubdomain.api.stellaconnect.net`. Agent Connect issues separate test and production key pairs, and each Serval connection targets exactly one environment. To connect both environments, set up two separate installs. Test keys do not work against production, and vice versa. ## Connect in Serval Paste your Agent Connect API key. The field is masked and the value is stored encrypted. Leaving it blank fails with "API Key is required". Paste the matching API secret. It is stored encrypted and is only ever used inside Serval to sign tokens. Leaving it blank during setup fails with "API Secret is required". Enter your gateway host, for example `yoursubdomain.api.stellaconnect.net`. Pasting a full URL from your browser is fine - Serval strips a leading `https://` or `http://`, surrounding whitespace, and trailing slashes automatically. A blank value fails with "API Host is required (e.g. `subdomain.api.stellaconnect.net`)", and a host that does not end in `api.stellaconnect.net` fails with "API Host must end in `api.stellaconnect.net` (e.g. `subdomain.api.stellaconnect.net`)". Serval trims all values before saving, so stray whitespace from copy-paste cannot break authentication. When editing an existing connection, the API Key and API Secret appear masked (dots plus the last four characters of the stored value). Leaving the API Secret masked or blank keeps the stored secret. The API Key works differently: Serval requires it on every save, so re-enter your API key (use the field's edit control) before saving any change - a save with the API Key left masked or blank is rejected with "API Key is required". The API Host is shown in clear text and must pass validation on every save. ## Verifying the connection The integration ships one health check: **Test Medallia Agent Connect Connection** - signs a fresh token with your stored API secret and makes a tiny query against the Data Return API (a one-second time window, so almost no data comes back). Because that API requires a valid token and API key, any successful response proves Agent Connect accepted both credentials and that the host is correct. * On success: "Successfully authenticated with Medallia Agent Connect and reached the API gateway." * On failure: "Unable to connect to Medallia Agent Connect. Verify your API key, API secret, and API host are correct and that the key has not been revoked on the Agent Connect Integrations page." If the connection test is green but a specific workflow call fails, check that your API key has access to that Agent Connect API family, and - for Data Return queries - that date filters carry an explicit UTC offset (for example `2026-04-21T00:00:00.000+00:00`). ## Gotchas and troubleshooting Agent Connect issues independent test and production API key and secret pairs, and each Serval install targets exactly one environment. Test keys do not work against production and vice versa - mixing environments is a common cause of authentication failures. Make sure the key, secret, and the account you intend to reach all belong to the same environment. Serval strips a leading `https://` or `http://`, surrounding whitespace, and trailing slashes from the API Host before validating, so copy-pasting from the browser URL bar works. But the resulting host must end in `api.stellaconnect.net` - any other host is rejected at save time, and Serval independently refuses to attach your credentials to requests aimed at hosts outside Medallia's Agent Connect gateway. The connection test queries the Data Return API. If your API key does not have access to that part of Agent Connect, the health check fails even though the credentials may be valid for other endpoint families. Ask your Agent Connect administrator to enable Data Return access for the key. When you edit an existing connection, the API Key and API Secret display as masked values (dots plus the last four characters). Leaving the API Secret masked or blank keeps the stored secret - the masked placeholder never overwrites the real value. The API Key does not behave the same way: a save with the API Key left masked or blank is rejected with "API Key is required", so keep your API key on hand and re-enter it whenever you save changes to this connection. All values are trimmed before saving, so trailing whitespace cannot silently corrupt the signing key. Agent Connect rejects access tokens that are not freshly issued, so a token cannot be created once and reused. Serval signs a brand-new token on every outbound request (each one expires after 60 seconds as an extra safeguard). The generic custom HTTP integration only supports static headers and cannot re-sign per request, which is exactly why this native integration exists - use it instead of a custom HTTP connection. Per Medallia's [authentication documentation](https://docs.medallia.com/en/agent-connect/api/authentication), Agent Connect expects the Authorization header to contain the bare signed token, not "Bearer" followed by the token. Serval handles this automatically; if you are comparing against your own manual API tests, do not add a Bearer prefix. Medallia documents Data Return date filters such as `created_at_gte` and `created_at_lte` as ISO 8601 timestamps with an explicit offset from UTC, in the form `YYYY-MM-DDTHH:MM:SS±HH:MM` (for example `2019-12-20T00:00:00-05:00`). See [Filter by time or sequence](https://docs.medallia.com/en/agent-connect/api/data-return/filter-by-time-or-sequence). Serval's connection health check sends its one-second window this way, as UTC values ending in `+00:00` (for example `2026-04-21T00:00:00.123+00:00`). Format the date filters in your own Data Return workflows the same way. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Medallia Agent Connect integration. # Microsoft Graph Source: https://docs.serval.com/sections/integrations/microsoft-graph Connect Microsoft 365 and Entra ID to Serval to sync users, groups, and enterprise apps, manage Intune devices and licenses, automate mail and calendar, and index SharePoint and OneDrive for the Serval knowledge base. ## About Microsoft Graph Microsoft Graph connects Serval to Microsoft 365 and Entra ID through the Microsoft Graph API, giving your workflows and ingestion access to Entra ID users and groups, enterprise applications, Microsoft Intune device management, license and subscription management, mail and calendar, and SharePoint/OneDrive content for the Serval knowledge base. Anything in the Microsoft Graph API surface can be reached through Serval's proxied request layer, subject to the permissions you grant. **Authentication:** Sign in with Microsoft (recommended; OAuth 2.0 with delegated permissions), or a Custom Application (OAuth 2.0 client credentials with application permissions). **Data sync:** Background sync of Entra ID users, Entra Security Groups (full sync every 16 hours, delta every 4), Entra Microsoft 365 Groups (full sync every 8 hours, delta every 4), and enterprise applications with their app role assignments - plus continuous indexing of SharePoint and OneDrive content as a knowledge source. ## What the Microsoft Graph integration enables | Capability | Description | | - | - | | Entra ID user directory sync | Ingests all Entra ID (Azure AD) users on a recurring schedule so they are available throughout Serval. | | Entra group sync and membership provisioning | Syncs Entra Security Groups (access control - full sync every 16 hours, delta every 4) and Entra Microsoft 365 Groups (collaboration - full sync every 8 hours, delta every 4) as separate resource types, each with a Member entitlement. Serval can add or remove users from either group type for access requests and provisioning workflows. | | Enterprise application sync | Ingests Entra enterprise applications and their app role assignments, mapping who has access to which app. | | Microsoft Intune device management | Read Intune managed devices, configuration policies, apps, RBAC, and service settings. With the read/write preset, manage Intune and perform privileged device actions such as wipe and retire. | | SharePoint and OneDrive knowledge base | Indexes SharePoint sites and OneDrive document libraries as a Serval knowledge source for AI answers. | | License and subscription management | Read directory and subscription data, and read or update license assignments from workflows. | | Mail and calendar automation | Read, write, and send mail and manage calendars from workflows. | | Groups, Teams, and guest access actions | Create teams, manage groups, and invite or manage external guests in Microsoft Teams teams and channels from workflows. | | Full Microsoft Graph API access | Any Microsoft Graph API endpoint can be called from workflows through Serval's authenticated proxied requests, subject to the permissions granted to the connection. | Anything defined in the [Microsoft Graph API](https://learn.microsoft.com/en-us/graph/api/overview) can be accessed through Serval. Looking for Microsoft Teams help desk and channel automation, or Exchange Online management? Those are separate integrations with their own pages: [Microsoft Teams](/sections/integrations/microsoft-teams) and [Exchange Online](/sections/integrations/exchange-online). ## Get your credentials There is nothing to create in Azure for this method. You connect using a Microsoft **work account** through Serval's official multi-tenant Entra application - personal Microsoft accounts are not supported. Use a work account that is allowed to consent to applications in your organization. For the integration to work organization-wide, the person connecting must check **Consent on behalf of your organization** on Microsoft's "Permissions requested" screen - this requires an admin. Microsoft re-confirms the full permission set on every connect and reconnect. Create an app registration in Microsoft Entra ID with a client secret and Microsoft Graph **application** permissions, then grant admin consent. See Microsoft's guide: [Register an application in Microsoft Entra ID](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app). Go to the [Azure Portal](https://portal.azure.com) or the [Microsoft Entra admin center](https://entra.microsoft.com) and sign in with admin privileges. Navigate to **App registrations** in the left sidebar and click **New registration**. Configure: Name e.g. "Serval Microsoft Graph Integration"; Supported account types: **Accounts in this organizational directory only**; Redirect URI: leave blank. Click **Register**. From the app's **Overview** page, copy the **Application (client) ID** and **Directory (tenant) ID** - you'll paste both into Serval's connect form. Navigate to **Certificates & secrets**, click **New client secret**, choose an expiration, and click **Add**. Immediately copy the secret **Value** - this is the "Client secret value" field in Serval. Copy the secret **Value**, not the Secret ID. The value is only visible immediately after creation - if you navigate away, you'll need to create a new secret. Navigate to **API permissions** → **Add a permission** → **Microsoft Graph** → **Application permissions**, and add the permissions your use cases need (e.g. `User.Read.All`, `Group.Read.All`, `Directory.Read.All`, `Sites.Read.All`, `Files.Read.All`, `DeviceManagementManagedDevices.Read.All`, `LicenseAssignment.ReadWrite.All`). The integration's effective permissions are exactly what you grant here - see the [Microsoft Graph permissions reference](https://learn.microsoft.com/en-us/graph/permissions-reference) for what each permission allows. Click **Grant admin consent for \[Your Organization]** and confirm. Verify every permission shows "Granted for \[Your Organization]". Granting admin consent requires an appropriately privileged role - see [Microsoft's prerequisites](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/grant-admin-consent?pivots=portal#prerequisites). Without this step, none of the permissions take effect and the connection will fail with a consent error. ## Connect in Serval In the Microsoft Graph connect modal, choose to connect with your Microsoft **work account**. Every connection requests a base set of read permissions (your profile and basic details of other users, directory data, groups and group memberships, Teams team and channel details, channel messages, SharePoint and OneDrive content, plus offline access so Serval can refresh tokens automatically). On top of that, check the presets you need: | Preset | What it enables | | - | - | | **OneDrive and SharePoint** (checked by default) | Gather knowledge from OneDrive and SharePoint (`Files.Read`, `Files.Read.All`) | | **Manage Licenses and Subscriptions** | `Directory.Read.All`, `LicenseAssignment.Read.All`, `LicenseAssignment.ReadWrite.All`, `Subscription.Read.All` | | **Mail and Calendar** | `Mail.Read`, `Mail.ReadWrite`, `Mail.Send`, `Calendars.Read`, `Calendars.ReadWrite` | | **Groups and Collaboration** | `Group.Read.All`, `Group.ReadWrite.All`, `Team.Create`, `Team.ReadBasic.All` | | **Teams Guest Access** | `User.Invite.All`, `User.Read.All`, `Team.ReadBasic.All`, `TeamMember.ReadWrite.All`, `ChannelMember.ReadWrite.All`, `Channel.ReadBasic.All`, `GroupMember.ReadWrite.All` | | **Microsoft Intune (Read-only)** | `DeviceManagementManagedDevices.Read.All`, `DeviceManagementConfiguration.Read.All`, `DeviceManagementApps.Read.All`, `DeviceManagementServiceConfig.Read.All`, `DeviceManagementRBAC.Read.All` | | **Microsoft Intune (Read/write)** | The read/write equivalents of the above, plus `DeviceManagementManagedDevices.PrivilegedOperations.All` for privileged actions like wipe and retire | Need something not in a preset? Use the **All permissions** search to add individual permissions from the full catalog. Sign in with your work account. Serval always asks Microsoft to re-confirm permissions, so you'll see the full list on Microsoft's "Permissions requested" screen. For org-wide use, check **Consent on behalf of your organization**, then accept. Serval detects your tenant ID and tenant name automatically and stores the granted permissions. Tokens refresh automatically - no maintenance needed. Reconnecting pre-selects your currently granted permissions, so adding a preset later is just: reconnect, check the new box, re-consent. Fill in Serval's **Configure Microsoft Graph** form. All four fields are required. A descriptive name for this integration instance. Free text; placeholder "e.g., My Microsoft Graph". The tenant GUID from the app registration's Overview page; placeholder "e.g., 12345678-1234-1234-1234-34567890abcd". If it's wrong, Serval reports a Microsoft AADSTS50034 error: > The tenant '\' does not exist or could not be found. > Please verify the Tenant ID in the Azure Portal. The application GUID from the app registration's Overview page; placeholder "e.g., 12345678-1234-1234-1234-34567890abcd". If Microsoft can't find the app (error AADSTS700016), Serval reports: > The Microsoft application with client ID '\' was not found in the directory '\'. > This can happen if: > • The application has not been installed by an administrator > • The application has not been consented to by any user > • You may have provided the wrong Client ID > • You may have provided the wrong Tenant ID > > Please verify your Client ID and Tenant ID in the Azure Portal. A password field; placeholder "Value from App registration, Certificates and secrets". Paste the secret **Value** (not the Secret ID). If the secret is wrong (error AADSTS7000215), Serval reports: > The client secret provided for application '\' is invalid. > Please verify the client secret in the Azure Portal and update it in Serval. **Editing later:** the stored client secret is shown obfuscated when you reopen the form. On update, leaving any field blank keeps its existing value - only fill in what you want to change. Each error message above is also followed by the original Microsoft error detail, which includes the AADSTS code. ## User sync settings User sync runs on the integration's settings page under **User Sync**. Two switches control who becomes a Serval user; both require the organization admin role. * **Create new users**: when on, user sync creates a Serval user for anyone it doesn't recognize. When off, it only updates people who already exist and skips the rest. * **Exclude guest accounts**: when on, the built-in Microsoft Graph user sync skips Entra ID guest accounts (external people invited into your tenant with a `userType` of `Guest`, listed under **Users > Guest users** in the Microsoft 365 admin center). Guests that an earlier built-in sync already created in Serval are retired on the next sync, the same way user sync handles a user removed from the directory. Built-in Microsoft Graph user syncs have this on by default. When off, guests sync like members. A new custom-only user-ingestion configuration starts with guest exclusion off. Customizing an existing built-in sync keeps its current setting. If guest exclusion is on, the workflow must provide a guest classification for every returned user or the sync fails. With **Deactivate absent users** off, excluded guests that were synced previously remain active. Entra ID's **Active users** list includes guests whose sign-in is enabled, so a guest can appear both there and under **Guest users**. The **Exclude guest accounts** switch keys off `userType`, not the sign-in state. ## SharePoint site-group permissions This step is optional, and it applies to Custom Application connections only. Set it up when SharePoint documents get their access from classic site groups. Classic SharePoint site groups - Owners, Members, Visitors, and any custom group you create on a site - are not exposed through the Microsoft Graph API. Reading their membership requires the SharePoint REST API, which issues app-only tokens only to a client that authenticates with a certificate. A client secret is not enough: SharePoint rejects secret-minted app-only tokens with "Unsupported app only token". Without a certificate, Serval cannot see who belongs to a site group, so it fails closed: documents whose access flows only through a site group stay hidden from the people who should see them. Serval generates the key pair for you, keeps the private key encrypted, and hands you only the public certificate to upload. Serval's SharePoint site-group permissions section showing a configured certificate with its expiry date, Download certificate and Regenerate buttons, the certificate thumbprint, and the numbered Set up in Azure steps Open the Microsoft Graph integration, go to **API Integration** → **SharePoint site-group permissions**, and click **Generate certificate**. Click **Download certificate (.cer)**. This file holds only the public certificate - the half Azure needs. Open [App registrations](https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps) in the Azure Portal, then go to your app → **Certificates & secrets** → **Certificates** → **Upload certificate**, and upload the `.cer` file. Serval's **Open Certificates & secrets in Azure** link takes you straight to the right blade for your app. Check that the thumbprint Azure lists matches the thumbprint Serval shows next to the certificate. The certificate proves who Serval is. A SharePoint permission decides what Serval may read. That permission lives on a second API, separate from the app's Microsoft Graph permissions. In the Azure Portal, open your app → **API permissions** → **Add a permission** → **APIs my organization uses** → **Office 365 SharePoint Online** → **Application permissions** → `Sites.Read.All`. Then click **Grant admin consent for \[Your Organization]**. `Sites.Read.All` on this API is enough to read site-group membership. Broader SharePoint permissions, such as `Sites.FullControl.All`, grant far more access than site-group ingestion needs. Back in Serval, run the **Verify SharePoint Site-Group Access** health check to confirm Serval can read site-group membership. Serval stores the private key encrypted and never exposes it - the download only ever contains the public certificate. Regenerating invalidates the previous certificate, so you must upload the new `.cer` to Azure and remove the old one. The app registration also needs the `Sites.Read.All` and `Files.Read.All` **Microsoft Graph** application permissions with admin consent - the same permissions SharePoint knowledge ingestion requires (see [Get your credentials](#get-your-credentials)). Grant those alongside the **Office 365 SharePoint Online** `Sites.Read.All` permission from the setup steps. Each API needs its own admin consent. The Graph permissions let Serval read documents, and the SharePoint permission lets Serval read site-group membership. ## Verifying the connection Serval runs ten health checks against your Microsoft Graph connection. **Test Microsoft Graph Connection** - Verifies Serval can authenticate by deliberately requesting a Graph resource that doesn't exist: a "resource not found" reply proves the token is valid. This check tests *only* authentication, never permissions. * Success: "Microsoft Graph authentication token is valid and working" * Failure: "Could not get a valid authentication token for Microsoft Graph. Please check your Client ID, Client Secret, and Tenant ID configuration." **List Microsoft Graph Users** - Confirms Serval can list users from your directory (up to 100). * Success: "Successfully listed \[number] users from Microsoft Azure AD" * Failure: "Unable to list users from Microsoft Azure AD." followed by a status-specific hint - for a permissions (403) failure: "The Microsoft Graph app may not have the required permissions. Check the app's permission configuration in Azure AD." **List Microsoft Graph Groups** - Confirms Serval can list groups from your directory (up to 100). * Success: "Successfully listed \[number] groups from Microsoft Azure AD" * Failure: "Unable to list groups from Microsoft Azure AD." followed by the same status-specific hints as the users check. **List Intune Managed Devices** - Confirms Serval can list managed devices from Microsoft Intune (up to 10). Requires the `DeviceManagementManagedDevices.Read.All` permission. * Success: "Successfully listed \[number] managed devices from Microsoft Intune" * Failure: "Unable to list managed devices from Microsoft Intune. This health check requires the DeviceManagementManagedDevices.Read.All permission." **Diagnose Microsoft Graph Permissions** - Probes every Graph capability Serval relies on (directory users and groups, SharePoint root site, site enumeration, site search, file reads, Intune devices) and reports which permission grants each one that is denied. Start here when several checks fail at once: it distinguishes a rejected token from missing permissions, and separates "SharePoint is unreachable" from "SharePoint is reachable but tenant-wide enumeration is not". On a connection that signs in as a user (delegated), it skips site enumeration, which Microsoft only allows for app-only connections, and tells you to reconnect instead of adding application permissions. * Success: "All \[number] probed Microsoft Graph capabilities are permitted: ..." * Failure: a per-capability list, e.g. "Enumerate all SharePoint sites - grant Sites.Read.All (needed for discovering sites to offer as knowledge bases ...)", followed by where to grant it in Azure. Remember that a permission which is added but never admin-consented still returns 403. **List SharePoint Sites** - Confirms Serval can enumerate the SharePoint sites available for knowledge base ingestion. * Success: "Successfully listed \[number] SharePoint sites" * Failure (enumeration denied): explains that the app either holds `Sites.Selected` rather than `Sites.Read.All`, or the tenant restricts site enumeration - and that ingestion of sites already granted keeps working either way. **Ingest SharePoint Permissions** - Confirms Serval can read SharePoint permission lists (site-level and per-file ACLs), which SharePoint knowledge permission ingestion depends on. * Success: "SharePoint permissions are readable: read \[number] site-level permission entries on ..." * Failure (blocked): if site enumeration is denied there is no site to probe, and the check reports itself blocked on **List SharePoint Sites** rather than guessing at a cause of its own. **Resolve User Group Memberships** - Confirms Serval can resolve a user's transitive Entra ID group memberships, which SharePoint knowledge permission enforcement performs at search time. **Check SharePoint Online License** - Verifies your Microsoft 365 tenant has a SharePoint Online license and the root site is accessible, which SharePoint knowledge base ingestion requires. * Success: "SharePoint Online is licensed and the root site is accessible" * Failure (no license): "This Microsoft 365 tenant does not have a SharePoint Online license. SharePoint knowledge base ingestion requires an active SPO license. Please assign a SharePoint Online license to the tenant, or remove the SharePoint knowledge source to stop sync failures." * Failure (permissions): "The Microsoft Graph app does not have permission to access SharePoint sites. Ensure the Sites.Read.All or Sites.ReadWrite.All permission is granted." **Verify SharePoint Site-Group Access** - Confirms Serval can read classic SharePoint site groups through the SharePoint REST API, which is what enables site-group permission ingestion. Only relevant if you set up [SharePoint site-group permissions](#sharepoint-site-group-permissions). * Success: "SharePoint site groups are readable: found \[number] site groups on "\[site]" - site-group permission ingestion is enabled." * Failure (no certificate): "A certificate credential is required for SharePoint site-group ingestion." Generate one in Serval and upload it to your app registration. * Failure (certificate not uploaded): "The generated certificate has not been uploaded to your Azure app registration yet (Microsoft error AADSTS700027)." Upload the downloaded `.cer` under **Certificates & secrets** → **Certificates** and re-run the check. * Failure (missing SharePoint API permission): "Serval authenticated with the certificate, but SharePoint rejected the request - the app registration is missing an application permission on the SharePoint API." Grant `Sites.Read.All` on **Office 365 SharePoint Online** and re-run the check. * Not applicable: on a Sign in with Microsoft connection, the check reports that site-group ingestion needs a Custom Application connection instead of failing. There's no certificate to configure on such a connection. If the connection test is green but the users, groups, Intune, or SharePoint checks fail, your credentials are fine - it's a **permissions** problem. The connection test only validates authentication. Reconnect with the right presets (Sign in with Microsoft) or add the missing application permissions and re-grant admin consent (Custom Application). ## Gotchas and troubleshooting Admin consent is required either way. With Sign in with Microsoft, org-wide operation requires checking **Consent on behalf of your organization** on Microsoft's "Permissions requested" screen. With a Custom Application, every Microsoft Graph application permission must be explicitly granted admin consent in the Azure portal - the integration can only do what was consented on the app registration. Serval surfaces these as (AADSTS65001): > The user or administrator has not consented to use the application '\'. > An administrator must grant consent for the application in the Azure Portal. or (unauthorized\_client): > The client is not authorized to request an access token for tenant '\'. > This typically means: > • The application is not properly configured in Azure AD > • Required API permissions have not been granted > • Admin consent may be required > > Please check the application configuration in the Azure Portal. **Fix:** in the Azure portal, open the app registration's **API permissions** page and click **Grant admin consent for \[Your Organization]**. The form field is literally labeled **Client secret value** - paste the secret's *Value*, not the Secret ID. The value is only visible in Azure immediately after creation. Expired secrets are surfaced explicitly (AADSTS700082): > The client secret for application '\' has expired. > Please generate a new client secret in the Azure Portal and update it in Serval. Other authentication failures you may see (invalid\_client, then the generic fallback): > Client authentication failed for application '\'. > Please verify the Client ID and Client Secret are correct. > Failed to authenticate with Microsoft Graph for tenant '\'. > Please verify your Client ID, Client Secret, and Tenant ID in the Azure Portal. **Fix:** create a new client secret in **Certificates & secrets**, copy its Value immediately, and update it in Serval. The scope presets in the connect modal only apply to the Sign in with Microsoft (delegated) flow. A Custom Application uses **application** permissions: its effective access is exactly the application permissions granted on the app registration. To get the equivalent of a preset, add the matching permissions under **API permissions → Microsoft Graph → Application permissions** and grant admin consent. The OAuth flow uses Microsoft's multi-tenant "organizations" sign-in endpoint, which accepts organizational work accounts only. Personal Microsoft accounts cannot be used. (Details: [Microsoft identity platform endpoints](https://learn.microsoft.com/en-us/entra/identity-platform/v2-protocols#endpoints).) If **List SharePoint Sites**, **Ingest SharePoint Permissions**, and **Verify SharePoint Site-Group Access** all fail with a bare `accessDenied` 403, that is usually **one** cause, not three: the app cannot enumerate sites tenant-wide, and the other two checks need a site to probe before they can test anything. The two configurations that produce it are the app holding `Sites.Selected` instead of `Sites.Read.All`, and a tenant that restricts site enumeration or search. In both cases **SharePoint knowledge ingestion of sites already granted to the app keeps working** - only automatic site discovery is affected. **Fix:** grant `Sites.Read.All` under **App registrations** → your app → **API permissions** → **Microsoft Graph** → **Application permissions**, then **Grant admin consent**. If `Sites.Selected` is intentional, these checks cannot verify your sites automatically - confirm ingestion health on the knowledge base itself, and run **Diagnose Microsoft Graph Permissions** to see the full capability breakdown. The List Intune Managed Devices check fails without the `DeviceManagementManagedDevices.Read.All` permission. Check the **Microsoft Intune (Read-only)** preset during OAuth connect, or grant the `DeviceManagement*` application permissions on a custom app. The **Read/write** preset additionally enables privileged device actions (wipe, retire) via `DeviceManagementManagedDevices.PrivilegedOperations.All`. SharePoint knowledge ingestion requires an active SharePoint Online license on the tenant - the SharePoint license health check verifies this by probing the root site. Either assign an SPO license or remove the SharePoint knowledge source to stop the sync failures. Access also requires the `Sites.Read.All` (or `Sites.ReadWrite.All`) permission. Generating the certificate in Serval is only half the setup - Entra rejects the token request until the matching public certificate is registered on the app registration. Serval reports: > This certificate has not been uploaded to your Azure app registration yet. **Fix:** download the `.cer` from **API Integration** → **SharePoint site-group permissions**, upload it in Azure under **App registrations** → your app → **Certificates & secrets** → **Certificates**, confirm the thumbprint matches, then re-run the **Verify SharePoint Site-Group Access** health check. Full walkthrough: [SharePoint site-group permissions](#sharepoint-site-group-permissions). A 401 with an empty `{}` body means Entra accepted the certificate and issued a token. SharePoint then rejected that token, because it carries no SharePoint role. The cause is a missing application permission on the **Office 365 SharePoint Online** API. That grant is separate from the app's Microsoft Graph permissions, so the Graph `Sites.Read.All` grant doesn't satisfy it. **Fix:** in the Azure Portal, open your app → **API permissions** → **Add a permission** → **APIs my organization uses** → **Office 365 SharePoint Online** → **Application permissions** → `Sites.Read.All`. Click **Grant admin consent**, then re-run the **Verify SharePoint Site-Group Access** health check. `Sites.Read.All` is enough. Broader SharePoint permissions, such as `Sites.FullControl.All`, grant more access than the check requires. Full walkthrough: [SharePoint site-group permissions](#sharepoint-site-group-permissions). Serval fails closed on permissions it cannot resolve. Classic site-group membership is unreadable through Microsoft Graph, so until you configure [SharePoint site-group permissions](#sharepoint-site-group-permissions), any document whose only grant comes from a site group stays hidden. A "Sign in with Microsoft" connection cannot do this - certificate credentials exist only on Custom Application connections. This is intentional. Serval ingests Entra Security Groups (access control; members can include users, devices, service principals, and nested groups; full sync every 16 hours) and Entra Microsoft 365 Groups (collaboration; user members only; full sync every 8 hours, since collaboration groups change more often) as distinct resource types with different sync schedules and approval semantics. Don't expect them to be merged. For Sign in with Microsoft: just reconnect. Serval pre-selects your currently granted permissions as checked presets plus individual extras, and Microsoft re-confirms the full set on every connect - so check the new preset, re-consent, done. For a Custom Application: add the application permissions on the app registration and re-grant admin consent; no change is needed in Serval. They live elsewhere. Microsoft Teams help desk and channel automation is the dedicated [Microsoft Teams integration](/sections/integrations/microsoft-teams), and Exchange Online (PowerShell) management is the [Exchange Online integration](/sections/integrations/exchange-online) - each has its own docs page. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Microsoft Graph integration. # Microsoft Teams Source: https://docs.serval.com/sections/integrations/microsoft-teams Connect Serval to your Microsoft Teams tenant to run a help desk in Teams channels and send messages from Serval workflows. ## About Microsoft Teams The Microsoft Teams integration connects Serval to your organization's Teams tenant so the Serval bot can power a help desk directly inside Teams - receiving channel messages, @mentions, thread replies, group chat messages, and DMs - and so workflows can send direct messages, channel threads, and group chat messages. There are two ways to connect: * **Serval's Teams app** (the default): setup is two one-time admin actions - a Microsoft administrator grants tenant-wide admin consent to Serval's managed application, and a Teams administrator uploads a Serval-generated bot app package to your organization's Teams app catalog. With this option there is nothing for you to register or configure on the Microsoft side - Serval manages its own application. * **Custom Application**: the bot runs as your organization's own Microsoft application instead of Serval's. You register an application in Microsoft Entra ID, create an Azure Bot that routes Teams messages to Serval, author and install your own Teams app package, and give Serval the application's credentials. This integration is separate from the [Microsoft Graph integration](/sections/integrations/microsoft-graph); if your team also needs mail, calendar, SharePoint, or Entra user lookups, connect both. **Authentication:** Serval's Teams app (default): one-time Microsoft admin consent against Serval's managed application, plus a Teams bot app package uploaded by a Teams administrator - no client ID, secret, or app registration for you to create. Custom Application: your own Entra app registration's Directory (tenant) ID, Application (client) ID, and client secret (OAuth 2.0 client credentials), entered in Serval's connect form and verified at connect time. **Data sync:** No background data sync. Inbound Teams messages are pushed to Serval in real time as they happen; outbound messages and API actions run on demand with short-lived tokens minted per request. API requests from Serval workflows can only reach Microsoft's `graph.microsoft.com` and `smba.trafficmanager.net` services. ## What the Microsoft Teams integration enables | Capability | Description | | - | - | | Help desk in Teams channels | The Serval bot receives channel messages, @mentions, thread replies, group chat messages, and DMs - powering ticket creation and in-thread AI responses. You activate a channel by @mentioning the bot in it; the channel then appears in Serval, where you assign it one of five modes: Disabled, Help desk (Always respond), Help desk (When relevant), Silent, or On demand. | | Send direct messages | Workflows can send a 1:1 direct message to any user in your tenant. Serval automatically installs its bot for that user first if needed. | | Send channel messages | Workflows can start a new thread in a channel. They accept a copied Teams link - a "Copy link to channel" link, a team link, or a channel message link - and auto-install the bot into the team if needed. Proactive bot messages work in standard and shared channels, not private channels. | | Send group chat messages | Workflows can post into an existing group chat using a copied chat link or a raw group chat ID (it starts with `19:` and typically ends in `@unq.gbl.spaces`). | | In-Teams bot commands | In a personal chat, select `create-ticket` from the command menu or type `/create-ticket` to create a support ticket from a short form. | | Microsoft Graph requests (Teams-scoped) | Advanced workflows can make arbitrary Microsoft Graph calls - catalog, install, membership, and channel queries - using the integration's tenant credentials. | | Bot Framework requests | Advanced workflows can call the Bot Framework Connector API directly for activities, adaptive cards, reactions, and conversation operations. | Anything defined in the [Microsoft Teams API](https://learn.microsoft.com/en-us/graph/api/resources/teams-api-overview) can be accessed through Serval. The automatic bot installation mentioned in the send actions above applies to Serval's Teams app only. Serval never installs a custom application: with a Custom Application connection, your organization uploads and installs its own app package, and any send to a place the app is not installed fails with an "is not installed" error naming your app ID (see [Custom application errors](#custom-application-errors)). ## Get your credentials There are no credentials to create. You will not register an Entra application, and you will never see or enter a client ID or secret - Serval uses its own managed application. Instead, two people in your organization each perform a one-time approval. Microsoft's official documentation on the admin consent flow is [here](https://learn.microsoft.com/en-us/entra/identity-platform/v2-admin-consent). Connecting requires a Microsoft administrator account that can grant tenant-wide admin consent. The consent screen lists every application permission Serval's app is configured with - this is expected. After connecting, a Teams administrator must upload Serval's bot app package as a custom app in the [Teams Admin Center](https://admin.teams.microsoft.com/policies/manage-apps) under **Teams apps → Manage apps**. To pre-install the Serval app for assigned users, add it to a [Teams Setup Policy](https://learn.microsoft.com/en-us/microsoftteams/teams-app-setup-policies) (**Teams Admin Center → Teams apps → Setup policies**) after the upload. Both admin actions are mandatory. Admin consent grants Serval API access; the bot app package upload is what allows the Serval bot to actually appear and operate in Teams. Skipping the upload is the most common cause of a "connected but not working" integration. Note that the upload alone does not install the app for anyone - after it, the Serval app still has to be added from the Teams app store before it can be @mentioned (covered in [Connect in Serval](#connect-in-serval) below). Run the Serval bot as an application your organization registers and controls. This is an advanced setup involving three separate Microsoft resources in your tenant: 1. An **Entra ID app registration** that holds the client ID, client secret, and Microsoft Graph permissions Serval uses. 2. An **Azure Bot** resource that tells Microsoft where to deliver inbound Teams messages. The Teams app manifest does not contain a webhook URL - routing from Teams to Serval is configured here. 3. A **Teams app package** that you author and upload so the bot can be installed in Teams. Serval does not generate a package for a custom application - the app is yours, so the package is too. Go to [Microsoft Entra ID → App registrations](https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade) and click **New registration**. Configure: Name e.g. "Serval - Teams"; Supported account types: **Accounts in this organizational directory only (Single tenant)** - this must later match the Azure Bot's **Type of App**. Leave the Redirect URI blank: Serval connects to a custom application with client credentials only, so there is no OAuth redirect. From the app's **Overview** page, copy the **Application (client) ID** and **Directory (tenant) ID** - you'll paste both into Serval's connect form. From the app's **API permissions** page, click **Add a permission** → **Microsoft Graph** → **Application permissions**, and add: * `Channel.ReadBasic.All` - resolve channel names and IDs when posting to channels * `Organization.Read.All` - read tenant metadata during setup and health checks * `Team.ReadBasic.All` - list teams and read team internal IDs for channel resolution * `TeamsAppInstallation.ReadWriteAndConsentSelfForChat.All` - let the Teams app install itself into chats and manage its own permission grants * `TeamsAppInstallation.ReadWriteAndConsentSelfForTeam.All` - let the Teams app install itself into teams and manage its own permission grants * `TeamsAppInstallation.ReadWriteAndConsentSelfForUser.All` - let the Teams app install itself for a user (personal scope) and manage its own permission grants * `User.Read.All` - resolve user directory info for mentions, DMs, and ticket assignment Then click **Grant admin consent for \[Your Organization]** and verify every permission shows **Granted** with a green check. Serval's connect-time verification fails without admin consent. Navigate to **Certificates & secrets**, click **New client secret**, choose an expiration, and click **Add**. Immediately copy the secret **Value** - this is the "Client secret value" field in Serval. Copy the secret **Value**, not the Secret ID. The value is only visible immediately after creation - if you navigate away, you'll need to create a new secret. In the [Azure portal](https://portal.azure.com), go to **Create a resource**, search for **Azure Bot**, and click **Create**. Fill in: * **Bot handle**: any unique name, e.g. `serval-teams-bot` * **Subscription** / **Resource group**: any subscription where you have Contributor - the Azure Bot doesn't need to live near anything else * **Pricing tier**: **Free (F0)** is sufficient * **Type of App**: **Single Tenant** - must match the **Supported account types** you chose for the Entra app. This field is fixed at creation time and can't be changed later. * **Creation type**: **Use existing app registration** * **App ID**: the **Application (client) ID** from the Entra app's Overview page * **App tenant ID**: the **Directory (tenant) ID** from the Entra app's Overview page On the new Azure Bot → **Settings** → **Configuration**, set **Messaging endpoint** to the endpoint for the deployment that hosts your organization: | Deployment | Messaging endpoint | | - | - | | United States (US1) | `https://svwebhook.us1.serval.com/teams` | | European Union (EU1) | `https://svwebhook.eu1.serval.com/teams` | | Self-hosted | `https://svwebhook./teams`, with your deployment's configured regional domain - see [Redirect and webhook URL shapes](/sections/self-hosting/deployment/integrations/index#redirect-and-webhook-url-shapes) | Then, under **Settings** → **Channels**, add the **Microsoft Teams** channel and accept the terms. The Teams channel must show **Running** before users can message the bot. Create a [Teams app manifest](https://learn.microsoft.com/en-us/microsoftteams/platform/resources/schema/manifest-schema) for your bot. Three things must line up with your Entra app for the bot to work with Serval: 1. `bots[0].botId` must be your **Application (client) ID** - Teams uses it to look up your Azure Bot's messaging endpoint. 2. `webApplicationInfo.id` must be the same client ID - this is what authorizes the resource-specific permissions below. 3. The bot's `scopes` decide where it can operate: include `personal` for DMs, `team` for channels, and `groupChat` for group chats. Under `authorization.permissions.resourceSpecific`, declare the application-type [resource-specific consent](https://learn.microsoft.com/en-us/microsoftteams/platform/graph-api/rsc/grant-resource-specific-consent) permissions the Serval bot relies on to read and send in the places it's installed: `ChatMember.Read.Chat`, `ChatMessage.Read.Chat`, `ChannelMember.Read.Group`, `ChannelMessage.Read.Group`, `ChannelMessage.Send.Group`, `ChannelSettings.Read.Group`, `TeamMember.Read.Group`, `TeamsActivity.Send.Chat`, `TeamsActivity.Send.Group` Zip `manifest.json` and the two icon PNGs at the **root** of the archive (no parent folder) - Teams rejects packages produced by macOS Finder's Compress or Windows Explorer's right-click zip because they add a wrapping folder or extra metadata. Upload the package at [Teams Admin Center → Manage apps](https://admin.teams.microsoft.com/policies/manage-apps), then install it where Serval needs to operate - Serval never installs a custom application for you: * **DMs**: the app must be in each recipient's **personal scope**. Add it to a [Teams Setup Policy](https://learn.microsoft.com/en-us/microsoftteams/teams-app-setup-policies) to pre-install it org-wide, or have each user add it from **Apps → Built for your org**. * **Channels and workflow channel messages**: add the app to each team (**Add to a team**). * **Group chat messages**: add the app to the chat. After the upload, Microsoft takes anywhere from a few minutes to an hour to propagate the app to your organization's catalog - until then it won't appear in searches. Three things on the Azure Bot must match the Entra app exactly, or Teams rejects inbound message delivery with a 401: the **App ID** must equal the Entra **Application (client) ID** (the same value as `bots[0].botId` in your manifest), the **App tenant ID** must equal the Entra **Directory (tenant) ID**, and the **Type of App** must match the Entra app's **Supported account types** (both Single Tenant, or both Multi Tenant). ## Connect in Serval In Serval, go to **Integrations** → **All integrations** → **Microsoft Teams** and click **Connect Microsoft Teams**. The connect dialog offers two options: **Connect Serval's Teams app** (recommended) - "Grant admin consent for Serval's managed Teams bot." - and **Custom Application** - "Advanced setup using an app registration created by your organization". In the connect dialog, choose **Connect Serval's Teams app**. There is no form to fill in for this option. You are redirected to Microsoft's admin consent screen. Sign in with a Microsoft administrator account and click **Accept**. Microsoft returns you to Serval and the integration is connected. Serval records your tenant and looks up your organization's display name (if the lookup fails, the raw tenant ID is shown instead). Back on the Microsoft Teams integration page in Serval, open the **API Integration** tab - a **Teams Bot Setup** section appears there once the integration is connected. Click **Download Teams Bot App** to download `Serval-Teams-Bot.zip`, generated specifically for your installation. Have your Teams administrator upload the ZIP at the [Teams Admin Center](https://admin.teams.microsoft.com/policies/manage-apps) under **Teams apps → Manage apps → Actions → Upload app** as a custom app. Uploading through the Teams client also works for basic use, but only Admin Center uploads are eligible for Setup Policies. After the upload, Microsoft takes anywhere from a few minutes to an hour to propagate the app to your organization's catalog. Until propagation completes, searching for Serval in the Teams client returns nothing - this delay is on Microsoft's side and cannot be skipped. The upload only publishes the app to your organization's catalog - it does not install it for anyone, and @mentioning Serval in a channel finds nothing until the app is added. In the Teams client, go to **Apps** in the left sidebar and search for **Serval**. The app appears under **Built for your org** - this is your organization's own uploaded package, not a public marketplace listing. Select it and click **Add**. To use Serval in a team's channels, also add it to that team: use the **Add to a team** option and pick the team whose channels you want to connect. In Teams, @mention Serval in any channel you want to use as a help desk. The channel then appears (in Disabled mode) under **Connected Channels** on the integration's Help Desk page in Serval, where you choose its mode - Disabled, Help desk (Always respond), Help desk (When relevant), Silent, or On demand. **Reconnect** re-runs the full Microsoft admin consent flow end-to-end and saves a fresh connection - there are no editable fields to update. The bot app package can be re-downloaded at any time; it is regenerated on every download. Choose **Custom Application** in the connect dialog and fill in the form. All four fields are required. A descriptive name for this connection. Free text; placeholder "e.g., My Microsoft Teams". This name also identifies the directory in error messages. The tenant GUID from the app registration's Overview page. A value that isn't a GUID is rejected before anything is saved: > Directory (tenant) ID must be a GUID, like 00000000-0000-0000-0000-000000000000. Copy it from your app registration's Overview page in the Azure portal. The application GUID from the app registration's Overview page - the same value as `bots[0].botId` in your app package. Non-GUID values are rejected: > Application (client) ID must be a GUID, like 00000000-0000-0000-0000-000000000000. Copy it from your app registration's Overview page in the Azure portal. A password field; placeholder "Value from App registration, Certificates and secrets". Paste the secret **Value**, not the Secret ID. Leaving it empty is rejected: > Client secret is required. Create one under Certificates & secrets in your app registration in the Azure portal. **What connecting verifies - and what it can't.** Before saving anything, Serval verifies the credentials end-to-end: it uses your tenant ID, client ID, and secret to request an app-only token for the Bot Framework API and another for Microsoft Graph - the two audiences Serval mints at run time. A mistyped ID, a bad secret, or missing admin consent fails at connect time with one of the errors in [Custom application errors](#custom-application-errors), and nothing is saved. What the probe **cannot** see is the Microsoft-side bot wiring: the Azure Bot resource, its messaging endpoint, its Teams channel, and your app package upload and installation. "Connected" therefore means *credentials verified* - if you haven't finished the Azure Bot and app package steps under [Get your credentials](#get-your-credentials), finish them now, then @mention the bot in a channel to connect it, exactly as in the last step of the default flow. **Editing later:** a Custom Application connection shows its credentials form on the integration's settings page (in place of the managed flow's Reconnect + package download). The stored client secret is shown obfuscated when you reopen the form; on update, leaving any field blank keeps its existing value - only fill in what you want to change. Every save re-runs the connect-time verification against the merged values. ## Verifying the connection The Microsoft Teams integration runs three health checks. **Microsoft Teams Connectivity** - lists a small sample of your teams through Microsoft Graph to verify the connection's application permissions work. Finding zero teams still counts as success. * Success: "Connected to Microsoft Teams. Found \[number] team(s) including: \[team names]" - or, with zero teams: "Connected to Microsoft Teams, but no teams found in the organization. Create a team in Microsoft Teams and try again." * Insufficient privileges: "Serval does not have the required permissions to access Microsoft Teams. Please ensure the Team.ReadBasic.All application permission is granted in your Azure AD app registration. After adding the permission, an administrator must click 'Grant admin consent'." * Access denied: "Access denied when connecting to Microsoft Teams. The Team.ReadBasic.All application permission may not be granted. Go to Azure AD → App registrations → API permissions and verify that Team.ReadBasic.All is listed and has admin consent granted." * Authentication failure: "Authentication failed when connecting to Microsoft Teams. Admin consent may have been revoked, or the app credentials are invalid. Try reconnecting the Microsoft Teams integration." * Not found: "The Microsoft Teams API endpoint was not found. This may indicate that Microsoft Teams is not enabled for your tenant." * Microsoft server error: "Microsoft Teams returned a server error. This is likely a temporary issue with Microsoft's API - please try again later." * Consent never granted: "Admin consent has not been granted for the Microsoft Teams integration. Please reconnect the integration - a Microsoft administrator must approve the consent prompt." * Anything else: "Unable to connect to Microsoft Teams. Please verify the integration is connected and the admin has approved the required permissions." **Bot App Catalog Presence** - searches your organization's Teams app catalog for the Serval bot app, checking each known Serval app identity until one is found. On a Custom Application connection this check is informational: Serval doesn't know your app package's identity, so it reports success without querying the catalog - "This connection uses a customer-provided Teams app, so Serval does not check the organization's app catalog for it. Manage the app package in Teams Admin Center." * Success: "Serval bot app is present in the organization's Teams app catalog (ID: \[app ID])." * Not found: "The Serval bot app was not found in your organization's Teams app catalog. An administrator needs to upload the app package (downloadable from this page) in the Teams Admin Center under 'Manage apps'. Without this, the bot cannot be installed to teams or users." * Insufficient privileges: "Serval does not have permission to query the Teams app catalog. Ensure the AppCatalog.Read.All application permission is granted in your Azure AD app registration and that an administrator has clicked 'Grant admin consent'." * Access denied: "Access denied when querying the Teams app catalog. The AppCatalog.Read.All permission may not be granted. Check Azure AD → App registrations → API permissions." * Authentication failure: "Authentication failed when querying the Teams app catalog. Admin consent may have been revoked, or the app credentials are invalid. Try reconnecting the Microsoft Teams integration." * Anything else: "Unable to query the Teams app catalog. Please verify the integration is connected and the admin has approved the required permissions." **Channel Resolution** - lists your teams, verifies the first team's internal ID is readable (required to work out which channel the bot was @mentioned in), then lists that team's channels. Zero teams is reported as success with a caveat. * Success: "Channel resolution is working. Team "\[name]" has internalId and \[number] channel(s)." - or, with zero teams: "Connected to Microsoft Teams, but no teams found in the organization. Channel @mention support requires at least one team." * Missing internal ID: "Serval can list teams but cannot read team internal IDs. This prevents Serval from resolving which channel the bot was @mentioned in. Please ensure the Team.ReadBasic.All application permission is granted with admin consent in Azure AD → Enterprise Applications → Serval → Permissions." * Insufficient privileges: "Serval does not have the required permissions to resolve Teams channels. Please ensure Team.ReadBasic.All and Channel.ReadBasic.All application permissions are granted in your Azure AD app registration with admin consent." * Access denied: "Access denied when resolving Teams channels. The required application permissions (Team.ReadBasic.All, Channel.ReadBasic.All) may not be granted. Check Azure AD → App registrations → API permissions." * Authentication failure: "Authentication failed when resolving Teams channels. Admin consent may have been revoked, or the app credentials are invalid. Try reconnecting the Microsoft Teams integration." * Anything else: "Unable to resolve Teams channels. This is required for channel @mention support. Please verify the integration is connected and the admin has approved the required permissions." Several of the failure messages above say to fix permissions "in your Azure AD app registration". What that means depends on the connection type. With **Serval's Teams app** there is no app registration in your tenant to edit - the Serval app appears under **Enterprise applications** instead, and you grant or repair permissions by re-granting tenant-wide admin consent: click **Reconnect** in Serval with a Microsoft administrator account, or review the Serval app in the Microsoft Entra admin center under **Enterprise applications**. With a **Custom Application** the guidance is literal: the app registration is yours, so add the missing permission under **App registrations → API permissions** and click **Grant admin consent**. If Microsoft Teams Connectivity passes but the bot can't send messages or be @mentioned, run Bot App Catalog Presence next. A green connectivity check only proves the credentials work - it says nothing about whether the bot app package was uploaded to your Teams app catalog. (On a Custom Application connection that check is informational, so verify the app package upload and installation directly in Teams Admin Center.) ## Gotchas and troubleshooting Connecting (admin consent) only grants API access. Until a Teams admin uploads `Serval-Teams-Bot.zip` to the org app catalog (**Teams Admin Center → Manage apps**), the bot cannot install itself anywhere: the Bot App Catalog Presence health check fails, and every send-message action fails. Direct messages report: > We couldn't find the Serval application in your Microsoft Teams app catalog. Please ask an administrator to upload it in Teams Admin Center before direct messages can be sent. Channel and group chat messages report that the Serval bot app was not found in the Teams app catalog and that an administrator must upload the app package in Teams Admin Center, followed by diagnostic details of each app identity Serval tried. The bot's chat and channel read/send rights come from resource-specific consent declared in the uploaded package - not from admin consent. (The Custom Application equivalent of this gotcha is the "is not installed" family of errors - see [Custom application errors](#custom-application-errors).) Two separate causes look identical here, and they often stack: 1. **Propagation delay.** After the Admin Center upload, Microsoft takes anywhere from a few minutes to an hour to propagate the app to your tenant's catalog. Until then the app doesn't exist as far as the Teams client is concerned - searching "Serval" under **Apps** returns nothing. Wait and search again; a passing Bot App Catalog Presence health check confirms the upload itself worked. 2. **The app was never added.** Uploading publishes the app to your org's catalog but installs it for no one. Someone must add it in the Teams client: **Apps** in the left sidebar → search **Serval** (it appears under **Built for your org** - your organization's own uploaded package, not a public marketplace listing) → **Add**, and use **Add to a team** for the team whose channels you want to connect. Only then does the @mention picker find the bot. To skip the per-user add entirely, an admin can pre-install the app through a [Teams Setup Policy](https://learn.microsoft.com/en-us/microsoftteams/teams-app-setup-policies) (see below). On a Custom Application connection, "connected" proves only that the credentials can mint tokens - message delivery depends entirely on Microsoft-side wiring that Serval cannot check for you. Work through these in order: 1. **Messaging endpoint.** On the Azure Bot → **Settings** → **Configuration**, the endpoint must be exactly the one for your deployment (see [Point the messaging endpoint at Serval](#get-your-credentials)) - re-check for typos. 2. **Teams channel.** On the Azure Bot → **Settings** → **Channels**, **Microsoft Teams** must show **Running**. 3. **Tenant-mode match.** The Azure Bot's **Type of App** must match the Entra app's **Supported account types** (both Single Tenant, or both Multi Tenant), and its **App ID** and **App tenant ID** must equal the Entra app's client and tenant IDs. A mismatch makes Teams reject delivery with a 401 before anything reaches Serval. 4. **App package installed.** The manifest's `bots[0].botId` must be the same client ID you entered in Serval, and the package must be uploaded and added where you expect the bot to respond. Serval never installs a custom application - if a workflow sends to a place your app package hasn't been installed, Microsoft's Bot Framework rejects the send and Serval reports which scope is missing, naming your app ID: > Your Teams app (app ID \[your app ID]) is not installed in the user's personal scope. Install your app package in Teams Admin Center (org-wide or via an app setup policy), then retry. > Your Teams app (app ID \[your app ID]) is not installed in the target team. Install your app package in Teams Admin Center (org-wide or to the team), then retry. > Your Teams app (app ID \[your app ID]) is not installed in the group chat. Install your app package in Teams Admin Center and add it to the chat, then retry. Each message ends with the underlying send error from Microsoft. The fix is always on your side: install the app package in the named scope, then retry the send. You can switch an existing connection between the two options in either direction without disconnecting, as long as you stay on the same Microsoft tenant - connecting the other option with the same Directory (tenant) ID swaps the stored credentials on the existing connection, and your connected channels and their modes survive the switch. The Teams side does not switch itself: the two options are different Microsoft applications, so you must also swap the app package in Teams. Moving to a custom application, upload and install your own package (Serval stops offering the `Serval-Teams-Bot.zip` download for a custom connection - requesting it answers "No app package exists for a custom app install"). Moving back to Serval's app, re-run the admin consent flow, then download and upload `Serval-Teams-Bot.zip` again. Until the matching package is installed, sends fail with the errors above. Serval never reveals its own application's secret: opening the credentials form on a connection that currently uses Serval's Teams app shows only the connection's name and tenant ID, and switching to a custom application always requires entering your own client ID and secret. Working out which channel the bot was @mentioned in requires reading each team's internal ID. The Channel Resolution health check detects this exact failure: "Serval can list teams but cannot read team internal IDs. This prevents Serval from resolving which channel the bot was @mentioned in..." If channel @mentions aren't creating tickets, run this health check first. The Bot App Catalog Presence health check and the auto-install step in every send-message action query your Teams app catalog. A permissions denial here maps to the literal guidance: ensure AppCatalog.Read.All is granted and an administrator has clicked 'Grant admin consent'. (Both behaviors belong to Serval's Teams app - on a Custom Application connection the catalog check is informational and sends never query the catalog.) Token failures are translated into plain messages. The directory or tenant named in them is the organization name Serval recorded when you connected (or the raw tenant ID if the name lookup failed). On Serval's Teams app: * AADSTS700016: "The Serval application was not found in the directory '\[organization name]'. This usually means admin consent has not been granted or has been revoked. Please reconnect the Microsoft Teams integration to grant admin consent again." * AADSTS65001: "Admin consent has not been granted for the Microsoft Teams integration. Please reconnect the integration - an administrator must approve the consent prompt." * unauthorized\_client: "The Serval application is not authorized for tenant '\[organization name]'. This typically means admin consent needs to be granted. Please reconnect the Microsoft Teams integration." * AADSTS7000215: "The client secret for the Serval application is invalid. Please contact Serval support." - that one is a Serval-side issue, not something you can fix. For all customer-side cases, the fix is the same: **Reconnect** the integration with a Microsoft administrator account. The same AADSTS conditions on a Custom Application connection produce messages about *your* app registration instead - see [Custom application errors](#custom-application-errors). Each downloaded `Serval-Teams-Bot.zip` is stamped with your specific installation's identity. If the catalog app doesn't match the connected integration, direct messages report: > We found the Serval application in your Microsoft Teams app catalog, but couldn't install it with the current Microsoft Teams integration configuration. Please ask an administrator to verify the Microsoft Teams integration is configured for the correct Serval application. Channel messages similarly report that Serval found the app but couldn't install it in the target team - which can also happen when the team hasn't granted the required resource-specific permissions or tenant policy blocks app-only installation. Re-download the package from the current integration settings page and re-upload it. Teams Setup Policies (auto-install for users) only see apps uploaded through the Teams Admin Center, not apps uploaded via the Teams client's 'Upload a custom app'. If the app was client-uploaded, also upload it at the [Teams Admin Center](https://admin.teams.microsoft.com/policies/manage-apps) under **Teams apps → Manage apps** before it appears in Setup Policy app search. The send-channel-message action only accepts a copied Teams link - a channel link, team link, or channel message link that includes the destination team. Anything else is rejected with: "Invalid Microsoft Teams channel identifier. Paste a copied Teams channel, team, or channel message link that includes the destination team." Private channels are also rejected - proactive bot messages require a standard or shared channel. (Group chats are more lenient: a raw chat ID starting with `19:` works there.) If the Serval bot isn't already a member of a group chat containing external or cross-tenant participants, automatic install fails. A user native to the hosting tenant must add the Serval bot to the chat once; subsequent group chat messages then succeed. Teams has its own application (Serval's managed app or your custom one), its own connect flow, and its own tenant-scoped connection - it does not use or require the [Microsoft Graph integration](/sections/integrations/microsoft-graph). Workflows that combine Microsoft 365 user lookups with Teams messaging need both integrations connected. With **Serval's Teams app** there are no credential fields, so there is nothing to edit later - **Reconnect** re-runs the Microsoft admin consent flow end-to-end and saves a fresh connection, and the **Teams Bot Setup** / **Download Teams Bot App** section appears once the integration is connected. With a **Custom Application** it's the mirror image: the settings page shows an editable credentials form, and there is no package download - the app package is yours to manage in Teams Admin Center. Microsoft's roughly 28 KB cap on message and adaptive-card payloads is not checked before sending; oversized messages fail at Microsoft's API with an opaque error. Send actions already retry transient failures automatically (up to 5 attempts) - workflow authors should not add their own retry loops on top. ### Custom application errors Errors on a Custom Application connection name *your* app registration and are fixable on your side. The connect form (and every later credential edit) reports verification failures inline; the same authentication errors can also surface later on sends if consent is revoked or the secret expires. | Serval reports | Cause and fix | | - | - | | "Instance name is required. Enter a name that identifies this connection, such as your organization's name." | The Instance Name field was left empty. | | "Directory (tenant) ID must be a GUID, like 00000000-0000-0000-0000-000000000000. Copy it from your app registration's Overview page in the Azure portal." | The tenant ID isn't a GUID - you may have pasted a domain name or a label. | | "Application (client) ID must be a GUID, like 00000000-0000-0000-0000-000000000000. Copy it from your app registration's Overview page in the Azure portal." | The client ID isn't a GUID. | | "Client secret is required. Create one under Certificates & secrets in your app registration in the Azure portal." | The secret field was left empty on a new connection. | | "Your app registration was not found in the directory '\[name]'. Verify the application (client) ID on this connection matches an app registration in that directory." | Microsoft answered AADSTS700016: the client ID doesn't exist in that tenant - wrong client ID, or wrong tenant ID. | | "The client secret for your app registration is invalid or expired. Create a new client secret in the Azure portal and update this connection." | Microsoft answered AADSTS7000215. Create a new secret under **Certificates & secrets**, copy its **Value**, and update the connection. | | "Admin consent has not been granted for your app registration. An administrator must grant admin consent to your app registration in the Azure portal." | Microsoft answered AADSTS65001. Open the app registration's **API permissions** page and click **Grant admin consent**. | | "Your app registration is not authorized for tenant '\[name]'. Verify the app registration exists in that tenant and has admin consent granted." | Microsoft answered `unauthorized_client` - usually a single-tenant app addressed through the wrong tenant, or missing consent. | | "Failed to authenticate with Microsoft Teams for tenant '\[name]'. Please try reconnecting the integration." | Any other authentication failure; the original Microsoft error detail follows the message. | | "Your Teams app (app ID \[your app ID]) is not installed in the user's personal scope. Install your app package in Teams Admin Center (org-wide or via an app setup policy), then retry." | A workflow direct message reached a user who doesn't have your app. Serval never installs a custom app - pre-install it via an app setup policy or have the user add it. | | "Your Teams app (app ID \[your app ID]) is not installed in the target team. Install your app package in Teams Admin Center (org-wide or to the team), then retry." | A workflow channel message targeted a team without your app. Add the app to that team. | | "Your Teams app (app ID \[your app ID]) is not installed in the group chat. Install your app package in Teams Admin Center and add it to the chat, then retry." | A workflow group chat message targeted a chat without your app. Add the app to the chat. | | "This connection uses a customer-provided Teams app, so Serval does not check the organization's app catalog for it. Manage the app package in Teams Admin Center." | Not an error: the Bot App Catalog Presence health check reporting that catalog presence isn't a health signal for an app Serval doesn't manage. | *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Microsoft Teams integration. ## Forms in Teams Teams form dialogs follow the personal help agent Teams rollout. They require **Enable personal help desk** in your organization settings. There isn't a separate forms switch or required setup test. When Serval asks you to complete a form in a ticket conversation or the personal help agent, select **Open form** to open it in a Teams dialog. Serval uses your Teams identity to verify that you're the active, linked requester for that form. Other people who can see the card can't fill it on your behalf. The dialog uses your Teams display language when Serval supports it, then your browser language, and English otherwise. On slower connections, the form may appear in English while your display language loads. You can start filling it out while translations load. With the updated Teams app package, Teams desktop and web keep the native loading indicator visible until the form or an error is ready. Mobile clients and older packages use Serval's loading indicator while the form loads. Select **View ticket** on the card to open the ticket in Serval. If a Teams dialog isn't available, **Open form** opens the form in your browser instead. After submission, the original card shows **Form submitted** and replaces **Open form** with **View form**. Select **View form** to review the submitted answers in a read-only dialog. If you leave a newly uploaded file unsaved for more than 24 hours, upload it again before saving or submitting. Files already saved with the form remain available. For forms created in the form builder, changes save automatically as you work. Select **Submit** when you finish to resume the ticket's workflow. Closing the dialog with **X** keeps only changes already saved. If saving fails, the dialog shows an error and a **Retry** button. If another session changes the form, reload it before continuing. If the dialog can't load the form, **Open in Serval** opens it in your browser. Form-builder forms containing repeaters or signed-document fields also offer a browser link. Use the browser experience if Teams sign-in is unavailable or you're a guest or cross-tenant user. Sovereign Microsoft cloud deployments use the browser experience. Existing messages retain their original links. ### Forms from older workflows Conversations and the personal help agent can also open forms from older workflows in a Teams dialog. These dialogs use the same **Open form**, **Form submitted**, and **View form** states. They support conditional fields, entity selections, file uploads, and document signing. Select **Submit** to save your answers and continue the workflow. These workflow forms don't save drafts automatically; closing the dialog discards unsent answers. If the submission response is interrupted, select **Check submission** before trying again. These dialogs use the same Teams SSO as form-builder forms. If you've already configured Teams form sign-in, you don't need another Entra or Okta application. Otherwise, update your existing Teams connection as described below. If Teams sign-in is unavailable, select **Open in Serval** to continue through your usual browser sign-in. Existing ticket-channel forms keep their current inline-card or browser experience. ### Update an existing Teams connection You can keep your existing Serval connection, bot, credentials, and Teams app ID. 1. In the connection's setup, download the updated **Teams Bot App** package. Use version **1.1.1** or later with the current form hostname and native loading experience. 2. Ask your Teams administrator to upload it as an update to the existing organization-catalog app and make the update available to users. 3. Complete additional Microsoft administrator consent if your tenant requires it. Serval manages the Entra application configuration. Update your existing Entra app registration and Teams package. Don't create a replacement bot or SSO application. 1. In Entra, set the API's `requestedAccessTokenVersion` to `2`. 2. Under **Expose an API**, set the **Application ID URI** to `api://msteams.serval.com/botid-` for Serval-hosted deployments. For a self-hosted deployment, replace `msteams.serval.com` with the form hostname provided by your Serval operator. Use your existing Entra **Application (client) ID** for ``. Expose the delegated `access_as_user` scope. 3. Authorize the Teams desktop/mobile client `1fec8e78-bce4-4aaf-ab1b-5451cc387264` and web client `5e3ce6c0-2b1f-4285-8d4b-75ee78787346` for that scope. 4. Add the optional `acct` claim to **access tokens**. Serval requires its member value, `0`; guest identities use the browser. 5. In the Teams manifest, add the form hostname to `validDomains`. Set `webApplicationInfo.id` to your existing Entra client ID and `webApplicationInfo.resource` to the same Application ID URI. Increase the package version and preserve the existing top-level app ID and bot ID. 6. Set the manifest's top-level `showLoadingIndicator` to `true` for native loading on desktop and web. This setting applies to every iframe dialog and tab page in your package. If your app includes other custom pages, they must also follow Microsoft's [native loading indicator lifecycle](https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/create-tab-pages/content-page#show-a-native-loading-indicator). 7. Upload the package as an update and complete any required tenant consent. 8. In **Enterprise applications → your app → Properties**, check **Assignment required?**. If it's **Yes**, every person who opens a form must be assigned under **Users and groups**; otherwise set it to **No** so anyone in the tenant can use forms. This setting lives on the enterprise application, not the app registration, and applies only to user sign-in. The bot itself authenticates as an application and is unaffected, so chat and direct messages keep working while every form fails. Follow Microsoft's [SSO app configuration](https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/authentication/tab-sso-register-aad) and [optional claims configuration](https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims) instructions. Merge these changes with your existing configuration so other API scopes remain available. Teams form dialogs are available only to the ticket's current requester. Team-private, deleted, and trashed tickets can't be accessed through a Teams form dialog. ### The form says "Sign in to continue" The dialog shows one message for every sign-in failure, so the cause has to come from Microsoft rather than from the message. Open **Entra → Monitoring → Sign-in logs**, select the **User sign-ins (non-interactive)** tab, and filter by the affected person. The entry records **Application** as the Teams client and **Resource** as your app, so filtering on your app's name in its enterprise-application blade returns nothing. Filter by user instead. The **Failure reason** on that row names the cause: | Sign-in error | Cause | Fix | | - | - | - | | `AADSTS50105` | The enterprise application requires user assignment and this person isn't assigned. Chat and direct messages still work, because the bot authenticates as an application and never passes this check. | Assign them under **Enterprise applications → your app → Users and groups**, or set **Assignment required?** to **No** | | `AADSTS65001` | Consent hasn't been granted for the tenant | **App registrations → your app → API permissions → Grant admin consent** | | `AADSTS500011` | Entra found no app in the tenant matching the Application ID URI the manifest requested in `webApplicationInfo.resource` | Make `webApplicationInfo.resource` exactly equal to the **Application ID URI** on the app registration | | `AADSTS65002` | The calling Teams client isn't pre-authorized for `access_as_user` | Add both Teams client IDs under **Expose an API** | A blank dialog with no message at all is a different failure: Teams refuses to load the page when the form hostname is missing from the manifest's `validDomains`. ### Okta and other Serval sign-in providers Your existing Okta or other Serval SSO application continues to work and doesn't need to change. Embedded forms authenticate through Microsoft Teams. Opening the form in a browser uses your normal Serval sign-in, including **Require SSO** and your identity provider's policies. Those Serval browser sign-in checks don't run inside the Teams dialog. ## Configure existing helpdesk channels through the API The [connected-channel API and workflow pattern](/sections/integrations/slack#configure-existing-helpdesk-channels-through-the-api) also supports Microsoft Teams. List the team's channels, optionally filter by the Teams integration's `serviceInstanceId`, and use the returned Serval connection `id` to set the mode. Teams supports `DISABLED`, `FULL_ASSIST`, `ASSISTANT`, `TICKET_ONLY`, and `ON_DEMAND`, each prefixed with `CONNECTED_SERVICE_MODE_`. Team only, team inbox, and redirect-to-DM modes are not supported and return a validation error. Disabled channels are included in listing, so setting `CONNECTED_SERVICE_MODE_FULL_ASSIST` activates an existing channel as **Help desk (Always respond)**. The API does not install the bot or create channel connections. # Mosyle Source: https://docs.serval.com/sections/integrations/mosyle Connect Mosyle to Serval with your Mosyle Business account email, password, and API Access Token so workflows can work with your Apple devices, users, and groups on demand. ## About Mosyle [Mosyle](https://mosyle.com) is an Apple device management (MDM) platform for businesses and schools. The Serval integration connects to your Mosyle Business account using your Mosyle account email, password, and an API Access Token. Serval signs in to Mosyle on your behalf with those credentials, giving your workflows on-demand access to everything the Mosyle Business API exposes - devices, users, and groups. Serval only ever sends these credentials to one host for this integration: businessapi.mosyle.com. **Authentication:** Mosyle account email + password + API Access Token, entered in a credential form. There is no OAuth or sign-in redirect flow. **Data sync:** None. No Mosyle data is ingested or synced into Serval - workflows reach Mosyle on demand. ## What the Mosyle integration enables | Capability | Description | | - | - | | Workflow API access | Workflows can call any Mosyle Business API capability. Serval handles the Mosyle sign-in automatically on every request. | | Device inventory and management | List and filter your managed Apple devices - Mac, iPhone and iPad, and Apple TV. | | User and group operations | Work with Mosyle users and groups - anything the Mosyle Business API exposes is available on demand. | | Connection health checks | Two built-in checks verify that your credentials work and that device management permissions are granted. | Anything the Mosyle Business API exposes can be accessed through Serval. The API reference lives inside your [Mosyle Business console](https://business.mosyle.com) under **Organization > API Integration**. ## Get your credentials You need three things: an API Access Token from the Mosyle Business console, plus the email and password of a Mosyle user account that is allowed to use the API. Sign in to your [Mosyle Business console](https://business.mosyle.com). Navigate to **Organization > API Integration**. Turn on the API integration profile for your organization. Copy the **Access Token** shown after enabling - you will paste it into Serval. Have the email and password of a Mosyle user with API access ready. Serval signs in as this user on every request. If your workflows touch devices, the account you choose must also have device management permissions in Mosyle. Without them, device operations (and the device health check) will fail even though the credentials are otherwise valid. Serval signs in as this user account. If the password changes or the account is deactivated in Mosyle, the connection stops working until you update the credentials in Serval. ## Connect in Serval Add a new Mosyle connection from your Serval integrations page. Fill in **Email** (required) - your Mosyle account email. Fill in **Password** (required) - your Mosyle account password. Fill in **Access Token** (required) - the token from **Organization > API Integration**. Click **Submit**. If installation fails, the form shows "Failed to install integration" (with details appended when available). All three fields are required. Leaving any of them empty blocks the form with the inline error "This field is required". There is no format checking beyond that, and Serval does not test the credentials when you save - a typo or stray space is accepted at save time and only surfaces when the health checks run or a workflow first calls Mosyle. Run the health checks right after connecting (see below). After saving, all three values - including the email - are displayed masked: bullet characters plus the last 4 characters. When you edit the connection later, any field you leave untouched or blank keeps its previously saved value, so you can rotate a single credential (for example, just the Access Token) without re-entering the other two. ## Verifying the connection Two health checks run against your connection: * **List Mosyle Users** - signs in with your stored credentials and retrieves your Mosyle users to confirm the connection works end to end. * Success: "Successfully connected to Mosyle and retrieved users (count: \[number])" * Failure: "Unable to connect to Mosyle. Please verify your email, password, and access token are correct." * **List Mosyle Devices** - retrieves your managed Mac devices to confirm the credentials are valid and device management permissions are granted. * Success: "Successfully connected to Mosyle and retrieved devices (count: \[number])" * Failure: "Unable to retrieve devices from Mosyle. Please verify your credentials and that device management permissions are granted." If **List Mosyle Users** passes but **List Mosyle Devices** fails, your email, password, and Access Token are fine - the Mosyle user Serval signs in as is missing device management permissions. Grant that user device management permissions in Mosyle, then re-run the check. ## Gotchas and troubleshooting Sign-in tokens are not cached. Every workflow request to Mosyle first triggers a fresh Mosyle sign-in with your stored credentials before the actual call is made. High-volume workflows therefore generate one Mosyle login per request, which can run into Mosyle's rate limiting sooner than the request count alone suggests. If a busy workflow starts seeing Mosyle errors, spread its requests out over time. Serval can only reach Mosyle's Business API service (businessapi.mosyle.com). Mosyle for Education (school) accounts and other Mosyle services are not reachable from Serval workflows. Each connection is pinned to a single Mosyle Business account. A note for whoever builds your workflows: the Mosyle Business API expects every operation - including simple lists of devices or users - to be submitted as a request with the operation described in the body, rather than a plain lookup. Serval pins requests to version 1 of the Mosyle Business API and fills in that version portion of the address automatically, so workflow builders do not need to include it. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Mosyle integration. # MyFantasyLeague Source: https://docs.serval.com/sections/integrations/myfantasyleague Connect a MyFantasyLeague.com fantasy football league to Serval so workflows can read league data and manage a franchise — rosters, lineups, waivers, trades, and live-draft picks. Currently in beta. ## About MyFantasyLeague MyFantasyLeague (MFL) is a fantasy football platform known for deeply customizable leagues and a complete public API. Connecting a league to Serval lets workflows read everything about it — rules, rosters, free agents, projections, standings, transactions — and act for your franchise: submit lineups, claim players on waivers or with FAAB bids, make immediate add/drops, manage injured reserve and the taxi squad, propose and answer trades, and make picks in a live draft. The MyFantasyLeague integration is currently in **beta**. **Authentication** Serval signs in to MFL with a franchise owner's username and password, and stores the password encrypted. It exchanges those credentials for MFL's `MFL_USER_ID` session cookie and reuses that cookie across calls, signing in again automatically when it expires or the password changes. Workflow authors never handle the credentials. Serval identifies itself with a User-Agent registered under MFL's API client program, which grants higher rate limits than anonymous clients get. Everything Serval can do is bounded by what that MFL account can do in the league: it acts as that owner's franchise, and commissioner-only operations work only if the account is the league commissioner. **League hosts** MFL serves each league from a numbered server (for example `www47.myfantasyleague.com`) and can move leagues between servers. Serval discovers the league's current host automatically when you connect and pins requests to it; site-wide data (the player database, injuries, ADP) is read from MFL's shared API host. ## What the MyFantasyLeague integration enables | Capability | Description | | - | - | | League setup and rules | Read the league configuration, franchises, divisions, lineup requirements, and scoring rules. | | Rosters and free agents | Read every franchise's roster (with IR/taxi status and salary info) and the available free agents. | | Player data | Read MFL's full player database, player profiles, the NFL injury report, projected and actual fantasy scores, and ADP draft data. | | Standings and schedules | Read league standings, weekly results, live scoring, the fantasy schedule, the NFL schedule, and the current NFL week. | | Lineups | Submit a franchise's starting lineup for a week. | | Waivers and add/drops | Read pending waivers; submit standard waiver claims, FAAB (blind-bid) claims, and immediate first-come-first-serve add/drops. | | IR and taxi squad | Move players on and off injured reserve and the taxi squad. | | Trades | Read pending trades and trade bait; propose trades (players, picks, FAAB dollars) and accept, reject, or revoke offers. | | Drafting | Read draft results and ADP, manage the pre-draft player queue, and make live-draft picks. | | Ad hoc API calls | Call any documented MFL request the connected account is allowed to make. | ## Get your credentials 1. Use the MFL account that owns your franchise (or create a dedicated one and add it as an owner of the franchise you want Serval to manage). 2. Find your **League ID** — the 4- or 5-digit number in your league's URL, for example `17268` in `https://www47.myfantasyleague.com/2026/home/17268`. 3. Note the **season year** your league is playing under (for example `2026`). ## Connect MyFantasyLeague to Serval 1. In Serval, go to **Settings → Integrations** and choose **MyFantasyLeague**. 2. Enter the account's **Username** and **Password**. 3. Enter the **League ID** and **Season**. 4. Save the connection. Serval looks the league up, discovers which MFL server hosts it, and verifies the account can access it. ## Gotchas and troubleshooting Most league data and every team action require the connected account to be an owner in the configured league. If the connection test fails with a "requires logged in user" message, the credentials are fine but the account isn't an owner in that league ID — or the league ID or season is wrong. A connection is scoped to a single league and season. If you play in several leagues, connect each one separately; at the start of a new season, update the connection's season (league IDs usually carry over year to year). When several leagues are connected, point each workflow at the right one — a workflow picks its league by the connection's instance ID, which is `leagueId-season` (for example `17268-2026`); a workflow that doesn't pick gets the team's oldest MyFantasyLeague connection. MFL answers a rejected call with an error payload rather than an error status. Serval reads the payload and raises the failure, so a permission problem surfaces as a failed step instead of an empty result. If a step fails with a message quoting MFL, that message came from MFL. MFL rate-limits by IP and asks clients not to retry failed calls aggressively. Serval retries reads after backing off, but never retries a write (waiver claim, lineup, trade, draft pick) on its own — a timed-out write may still have been applied, so check the result before resubmitting. MFL occasionally moves leagues between its numbered servers. Reads keep working, but if team actions start failing after a move, open the integration's settings and save them again — Serval re-discovers the league's host on every save. MFL updates its player database at most once per day and asks clients to read it no more than daily. Workflows that need it often should store it and refresh with the SINCE parameter rather than re-reading it on every run. The MyFantasyLeague integration is marked beta in the connect screen. Behavior and available capabilities may change. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your MyFantasyLeague integration. # n8n Source: https://docs.serval.com/sections/integrations/n8n Connect n8n Cloud or a self-hosted instance to manage workflows, executions, and automation resources from Serval. The n8n integration is in beta. It supports n8n's public REST API for workflows, executions, credentials, users, projects, tags, variables, and data tables. Available operations depend on your n8n version, plan, and API key permissions. Importing and exporting n8n packages is not supported because those endpoints require multipart uploads or return binary archives. ## Connect n8n 1. In n8n, open **Settings > n8n API** and create an API key. 2. On Enterprise plans, grant `workflow:list` for the connection check and only the additional scopes your automations need. Non-Enterprise keys have full access to the account's resources and capabilities. 3. In Serval, open **Settings > Integrations** and select **n8n**. 4. Enter your **API URL**, including HTTPS and the `/api/v1` suffix: * Cloud: `https://your-instance.app.n8n.cloud/api/v1` * Self-hosted: `https://automation.example.com/api/v1` * With a subpath: `https://automation.example.com/n8n/api/v1` 5. Enter your **API Key** and save. Serval stores the key as a secret and adds it to API requests. Workflow code receives the connection ID and API location. Changing the API URL requires entering a new key. For an instance on a private network, enable **Run on self-hosted workers**. The worker must be able to reach the instance and trust its TLS certificate. ## Verify the connection The connection check reads one workflow. Additional healthchecks read one execution and one tag, requiring `execution:list` and `tag:list` respectively. These checks do not modify resources or return workflow or execution contents. If a check fails, verify the URL, key expiration, and required scope. n8n's public API is unavailable during a free trial. An operation may also require a newer n8n version or an Enterprise plan. List responses include `nextCursor` when another page is available. Pass it as `cursor` on the next request; the SDK returns each page separately. See the [n8n API documentation](https://docs.n8n.io/connect/n8n-api) for operation details and permissions. # Nautobot Source: https://docs.serval.com/sections/integrations/nautobot Connect Serval to Nautobot so workflows can look up network devices, IP addresses, and circuits, and sync Nautobot's device, interface, and circuit inventory into Serval as assets. ## About Nautobot Nautobot is an open-source network source of truth and automation platform from Network to Code. It records network devices, their interfaces and IP addresses, circuits, and the locations they live in. Serval connects to your own Nautobot 3.x instance and reads from it. The integration never writes to Nautobot. The integration is marked **Beta** in the connect screen. For a Nautobot instance on a private network, enable **Run on self-hosted workers** for the connection and use an up-to-date worker and proxy. API requests then run from your network. The worker must be able to reach the instance and trust its TLS certificate. Publicly reachable instances can use Serval's cloud proxy. **Authentication:** A Nautobot API token for a dedicated service user. Serval stores the token encrypted and adds it to requests server-side, so workflows never handle it. Serval sends the token only to the Nautobot hostname saved on the connection. **Data sync:** No background sync starts when you connect. Data access is on demand through workflows, plus three installable ingestion workflows that sync Nautobot devices, interfaces, and circuits into Serval as assets. ## What the Nautobot integration enables | Capability | Description | | - | - | | Nautobot REST API access | Workflows use the "Nautobot API request" action to read Nautobot's network inventory: devices, interfaces, IP addresses, prefixes, VLANs, circuits, locations, racks, virtual machines, tenants, and more. | | Nautobot GraphQL access | The "Nautobot GraphQL request" action runs read-only GraphQL queries, which return an object and its related objects, such as a device with its manufacturer, location, and primary IP address, in one request. | | Asset ingestion | Installable workflows sync devices, interfaces that have an IP address, and circuits into Serval as external assets, each keyed by its Nautobot ID. | | Network lookups | Installable workflows find a device by name, serial number, or IP address, look up an IP address, and list the devices at a location. | | Connection health checks | Five built-in checks confirm the token works, the instance runs Nautobot 3.x, and the service user can read devices, interfaces, circuits, and GraphQL. | ## Prepare Nautobot Serval needs an **API token** for a Nautobot user whose permissions cover the data Serval should read. In Nautobot, create a dedicated user for Serval rather than using a person's account. A personal token stops working when that person leaves or their access changes. Create an object permission with the **view** action and assign it to the service user (or to a group it belongs to). Include the object types Serval reads: * **Devices:** devices, device types, manufacturers, platforms, software versions, roles, statuses, racks, and tags * **Locations:** locations and location types * **Interfaces and IP addresses:** interfaces, IP addresses, prefixes, and namespaces * **Circuits:** circuits, circuit terminations, circuit types, providers, and provider networks * **Tenancy:** tenants Nautobot returns only the objects a user may view. A related object the user cannot view, such as a device's manufacturer, comes back empty instead of failing the request. Add constraints to the permission if Serval should see only part of your network. Sign in as the service user, open the user's profile, and add an API token. Clear **Write enabled**, because Serval only reads. Nautobot then rejects any write made with the token, whatever the user's permissions allow. Copy the token. ## Connect in Serval Add a new Nautobot connection from your Serval integrations page. Enter the hostname of your instance, optionally with a port, for example `network.example.com` or `network.example.com:8443`. Nautobot must be served over HTTPS at the root of the host. A URL starting with `http://`, or one with a path, is rejected when you save. Paste the token you created for the service user. The token isn't tested when you save, so run the health checks right after connecting. To rotate the token, create the replacement token in Nautobot, edit the connection, paste only the new token, confirm the health checks pass, and then delete the old token in Nautobot. If you change the Nautobot URL on an existing connection, you must enter the token again, because Serval never sends a stored token to a different host. ## Verifying the connection The connection ships five health checks that make live calls to Nautobot: * **Validate API connection:** reads Nautobot's status endpoint. On success: "Successfully connected to Nautobot \[version]." It fails if the instance runs a Nautobot release other than 3.x. * **List devices:** reads one device and reports how many devices the token can see. * **List interfaces:** reads one interface and reports how many interfaces the token can see. * **List circuits:** reads one circuit and reports how many circuits the token can see. * **Query GraphQL API:** runs a one-device GraphQL query. Asset ingestion reads through GraphQL, so ingestion can't work until this check passes. A check can also pass with a message that starts "Connected, but no" and says none are visible to this token. That means the connection works but the service user can't see any of that object type. If Nautobot has those objects, review the user's object permissions. ## Syncing Nautobot inventory into Serval Install the ingestion workflows you need and use them as asset sync sources: | Workflow | Synced as assets | Asset key | | - | - | - | | Ingest Devices from Nautobot | Every device: name, serial number, asset tag, role, manufacturer and model, platform, software version, status, location and its parent locations, rack, tenant, primary IPv4 and IPv6 addresses with DNS names, tags, and custom fields | Nautobot device ID | | Ingest Interfaces from Nautobot | Interfaces with at least one IP address: name, type, MAC address, status, management-only flag, the parent device's ID and name, and each IP address with its parent prefix, netmask, and DNS name | Nautobot interface ID | | Ingest Circuits from Nautobot | Every circuit: circuit ID, type, provider, status, tenant, commit rate, install date, the location of each termination, tags, and custom fields | Nautobot circuit ID | Each interface record carries its parent device's Nautobot ID, which matches the external ID of that device's asset, so interfaces can be related to their devices. ## Gotchas and troubleshooting Confirm the hostname is correct and reachable from the worker or Serval deployment serving the connection. For private instances, check that **Run on self-hosted workers** is enabled and that your worker and proxy are up to date. Serval sees exactly what the service user may view. Object permissions with constraints, such as a single tenant or location, hide everything outside them, both from lookups and from ingestion. Related fields that come back empty on synced assets usually mean the user lacks view permission on that related object type, such as manufacturers or tenants. Every switch port is an interface in Nautobot, so syncing all of them would create far more assets than your devices, mostly ports with nothing a CMDB record needs. The interface workflow therefore syncs interfaces that have an IP address assigned. To sync every interface, edit the installed workflow and remove the `has_ip_addresses` filter. Nautobot has no built-in field for attributes such as environment. If you track them as Nautobot custom fields, they're included on each synced device and circuit under their custom field keys. The API request action is typed against the Nautobot 3.2 apps a network inventory needs: DCIM, IPAM, circuits, tenancy, virtualization, and extras. Endpoints added by Nautobot apps, such as Golden Config, and the string-match filter variants (`name__ic`, `name__nisw`, and so on) aren't part of it. Exact-match and range filters are. Serval requests Nautobot REST API version 3.2 on every REST call, so upgrading Nautobot within 3.x doesn't change the REST responses workflows receive. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Nautobot integration. # Navan Source: https://docs.serval.com/sections/integrations/navan Navan (formerly TripActions) is a corporate travel and expense platform; Serval connects to its Booking Data API so workflows can pull travel booking reports on demand. ## About Navan Navan (formerly TripActions) is a corporate travel and expense platform. The Serval integration connects to the Navan Booking Data API so your workflows can pull your company's travel booking report, including per-booking detail like passengers, pricing, policy compliance, and carbon emissions. The integration ships with one pre-installed workflow, "Get Navan Bookings from Last Week". Serval sends your credentials only to the Navan host for the region you select on the connection. That is api.navan.com for the US and app-fra.navan.com for Europe/Frankfurt. **Authentication:** OAuth 2.0 client credentials (Client ID + Client Secret issued from the Navan Admin Dashboard). No user sign-in, no consent screen, and no scopes to configure. You do select the region your Navan account is hosted in. **Data sync:** On-demand only. Navan data is read when a workflow step runs - there is no background sync, no webhooks, and no scheduled imports. ## What the Navan integration enables | Capability | Description | | - | - | | Pull the company booking report | Retrieve booking rows with rich detail: passengers, segments, pricing and fees, policy compliance, payment data, carbon emissions, and custom fields. | | Filter bookings by date and attributes | Narrow results by created, updated, or travel dates; by booking status (CANCELED, VOIDED, CONFIRMED, TICKETED, ACCEPTED); by booking type (HOTEL, FLIGHT, CAR, RAIL, TRANSPORTATION, BLACK\_CAR); or by a specific booking or trip identifier. | | Include per-booking transactions | Optionally embed transaction detail (ticket numbers, fees, taxes, totals, coupons) in each booking row. | | Page through large exports | Results are paginated, and responses include page metadata so workflows can walk the full report reliably. | | Pre-installed workflow: Get Navan Bookings from Last Week | Retrieves all travel bookings created in the last 7 days and returns the complete list with date range information. Runs without approval by default. | The integration currently models a single resource from the [Navan API](https://app.navan.com/swagger-ui/index.html): the company booking report. Other Navan endpoints are not yet available through Serval. ## Get your credentials Serval needs a Navan API credential - a Client ID and Secret Key - created from the [Navan Integrations settings](https://app.navan.com/app/admin2/en/settings/integrations). You must have access to the Navan Admin Dashboard to create one. Log in to Navan on the web, click the Navan logo in the top left, and select **Admin** - or go directly to the [Admin Dashboard](https://app.navan.com/app/admin2/en/dashboard). Navigate to **Travel**, then **Settings**, then **Integrations** in the left menu, or use the [direct link](https://app.navan.com/app/admin2/en/settings/integrations). Scroll to the **Navan API Credentials** section and click **Create new**. Enter a **Description** (this serves as the credential's name). Optionally restrict it by **Allowed IP Addresses** or **Subnet Mask**. Click **Create**. Copy both values from the confirmation pop-up - use **Copy All** to grab the Description, Client ID, and Secret Key together. Once the pop-up closes, the Secret Key is no longer accessible. Navan shows the Secret Key exactly once, in the creation pop-up. If you lose it, use **Rotate Key** on the credential to get a new secret with the same Client ID, then update the Serval connection. The Description and Client ID cannot be changed after creation. The **Edit** menu on an existing credential supports editing the allowed IP addresses or subnet masks, **Rotate Key** (new secret, same Client ID), and **Revoke**. ## Connect in Serval Find the Navan integration and start a new connection. A free-text label for the connection (placeholder: "My Company"). It is used as both the connection's identifier and its display name. Choose the region your Navan account is hosted in. **US (api.navan.com)** is the default, and an EU-hosted account must select **Europe / Frankfurt (app-fra.navan.com)**. The wrong region makes authentication fail. Paste the Client ID from your Navan API credential. Paste the Secret Key from your Navan API credential. After saving, this field displays masked (bullet characters plus the last 4 characters) with a control to replace it. There are no scopes to configure. Serval talks to the API host for the region you selected. The credential fields are not marked required, so the form will accept a blank submission. Bad or missing credentials only surface afterward through the connection test - double-check your values before saving. When editing an existing connection, you do not need to re-enter the Client Secret: leaving a field blank (or leaving the masked secret untouched) keeps the stored value. Only replace the secret when you have rotated the key in Navan. Connections made before the **API Region** dropdown existed keep working unchanged. They use the US host, and their settings form shows US selected. ## Verifying the connection The integration includes one health check, **Test Navan Connection**. It requests a small sample of your booking report covering the last 90 days - Navan requires date filters on booking queries, so the check supplies them automatically - and confirms that authentication succeeds and booking data is accessible. Serval also re-runs the health check automatically when you save changes to the connection. On success: "Successfully connected to Navan Booking Data API and retrieved booking information (\[number] total bookings available)" On failure (invalid credentials): "Unable to connect to Navan Booking Data API. The OAuth client credentials are invalid or expired. Please verify your Client ID and Client Secret in the Navan integration settings." If the connection test is green but a workflow returns no bookings, the date filters are the usual culprit: booking queries effectively require them, and the values must be epoch seconds. See "Booking queries return empty results" below. ## Gotchas and troubleshooting Every failure message starts with "Unable to connect to Navan Booking Data API." For failures Serval recognizes, a status-specific explanation follows; otherwise that base message appears alone. If Navan rejects the credentials (401), the message continues: "The OAuth client credentials are invalid or expired. Please verify your Client ID and Client Secret in the Navan integration settings." If the client lacks permission (403): "The OAuth client is not authorized to access Navan. Please ensure the client has been granted the necessary permissions in Navan." If Navan itself errors (500, 502, or 503): "Navan returned a server error during authentication. This is likely a temporary issue - please try again later." An EU-hosted account left on the US region cannot authenticate. Serval sends the OAuth token exchange to api.navan.com, which does not know a credential issued for a Frankfurt-hosted account. The exchange is rejected, so every request fails. Navan rejects the credential rather than reporting a region mismatch, so the connection test reads as an authentication problem and points you at your Client ID and Secret Key. Check the region first. To fix it, edit the connection, select **Europe / Frankfurt (app-fra.navan.com)**, and save. Serval re-runs the health check when you save, so you see the result immediately. Navan only shows the Secret Key in the creation pop-up. There is no way to view it again. Use **Rotate Key** on the credential in Navan's Integrations settings (you get a new secret with the same Client ID), then edit the Serval connection: choose to replace the masked Client Secret and paste the new value. The connect form's credential fields are not required, so a first-time submit with blank credentials is accepted by the UI. The problem only shows up when the connection test runs and reports invalid credentials. If this happens, edit the connection and fill in the Client ID and Client Secret. No. The settings screen shows the Client Secret masked (bullet characters plus the last 4 characters), and saving with a blank or untouched secret preserves the stored value - the same applies to the Instance Name and Client ID. Renaming the instance or changing the Client ID alone is safe. Only re-enter the secret when rotating the key in Navan. Navan's booking report expects date filters, and all date values must be epoch seconds (whole-number Unix timestamps) - not milliseconds and not ISO date strings. This applies to all six date filters: createdFrom, createdTo, updatedFrom, updatedTo, startDateFrom, and startDateTo. Missing filters or wrong units yield empty results or a request error. The pre-installed workflow and the health check both supply created-date filters automatically. There are no scopes to set. Navan does not use explicit scopes, because a single bookings-read capability always comes with the credential. There is no company domain or subdomain to enter either. The one host setting is the **API Region** dropdown, which chooses between api.navan.com for the US and app-fra.navan.com for Europe/Frankfurt. Booking report pages are zero-based: Serval's shipped workflow and health check start at page 0. The pre-installed workflow keeps requesting pages until the reported current page reaches the last page, and treats a response with no total page count as the end of the results. If you build your own pagination, also stop when a page returns fewer rows than you requested. The integration currently covers a single resource: the company booking report. There is no dedicated single-booking endpoint - to fetch one booking, filter the report by its booking or trip identifier instead - and Navan's people, policy, and invoice APIs are out of scope until they appear in the API specification. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Navan integration. # Neat (Beta) Source: https://docs.serval.com/sections/integrations/neat Connect Neat Pulse to manage meeting-room devices, rooms, and organization resources from Serval. The Neat integration is in beta. It supports the Pulse API for devices, firmware, rooms, locations, regions, profiles, users, notes, sensor data, and audit logs. You need a paid Neat Pulse plan. ## Connect the integration In Neat Pulse, open **Settings** and copy your **Organization ID**. Under **Settings > API keys**, select **Create API key**. Grant **Read** for connection checks. Add **Write** only if your workflows need to change devices or organization resources. Copy the key. Neat only displays it at creation. Open **Integrations > All integrations**, select **Neat**, and enter your **Organization ID** and **API Key**. Save the connection. Serval stores the API key as a secret and adds the bearer authorization header for requests to Neat. Workflow code receives the connection and organization IDs. Changing the organization requires a new API key. ## Hosting zones For a Pulse organization in Europe or the United States, use the same connection form with that organization's ID and API key. The public API and official Neat client use `api.pulse.neat.no` and identify the organization through `/v1/orgs/{organizationId}`. There is no region selector in this integration. Neat hosts European organizations in the Netherlands and United States organizations in Washington. Neat manages your Pulse organization's hosting zone. Connecting Serval doesn't change it. See the [Neat data residency documentation](https://support.neat.no/article/data-residency/) for zone details and migration requests. ## Verify the connection The connection check lists devices. Additional read-only healthchecks list rooms, locations, and profiles. An empty organization can pass these checks. If a check fails, verify the organization ID, paid Pulse plan, and the key's Read scope. Replace a revoked key in the Serval connection settings. ## Send requests Call `neat.apiRequest` with a path such as `/endpoints` or `/rooms/{id}`. Serval supplies `/v1/orgs/{organizationId}` from your connection settings. Pass path parameters, query parameters, and JSON request bodies. Audit logs support `pageToken`, `pageSize`, `from`, and `to`. Pass the returned page token to fetch subsequent pages. The SDK returns one response per call. Neat delivers device configuration asynchronously. A successful request means Neat accepted it. Check the device state to confirm the current settings. Device resets, device removal, firmware changes, user changes, and key rotation can disrupt devices or access. Rotating the connected API key through a workflow doesn't update the stored Serval credential. Save the replacement key in Serval before the old key expires. The Neat reference currently omits field definitions for factory-reset, firmware update, and room-profile assignment request bodies. Those bodies accept arbitrary JSON objects, so confirm the payload with Neat before using those operations. See the [Neat API reference](https://api.pulse.neat.no/docs/) and [API key setup guide](https://support.neat.no/article/managing-api-accounts-on-neat-pulse-management-platform/). # Netskope Source: https://docs.serval.com/sections/integrations/netskope Connect your Netskope tenant to Serval so workflows can read security alerts and events, manage URL block/allow lists, triage DLP and malware incidents, manage SCIM users and groups, and look up URL categorizations. ## About Netskope [Netskope](https://www.netskope.com) is a SASE/SSE platform: a secure web gateway, CASB, and DLP engine that inspects your organization's cloud and web traffic. Connecting your Netskope tenant to Serval lets workflows read security alerts and events (DLP, malware, policy, UBA, and more), manage URL block/allow lists and deploy the changes, triage DLP and malware incidents (update status and assignment, read forensics, add notes), manage SCIM users and groups, and look up how Netskope categorizes a URL. Serval talks only to your own tenant's address (for example `mycompany.goskope.com`) and attaches your API token to every request as the `Netskope-Api-Token` header - workflow authors never see or handle the token. **Authentication:** API token (a REST API v2 service-account token, plus your tenant hostname) **Data sync:** On-demand only. There is no background sync or scheduled polling - Serval calls the Netskope API only when a workflow runs, and verifies the connection with lightweight read-only health checks. ## What the Netskope integration enables | Capability | Description | | - | - | | Alert & event reads | Query alert, application, audit, network, page, and infrastructure events over a time window, or iterate complete event streams with the cursor-based data-export endpoints (per-type alert feeds: DLP, malware, malicious site, policy, UBA, CTEP, compromised credential, quarantine, remediation, security assessment, watchlist). | | Incident triage | Update DLP/malware incident status, severity, and assignment, read DLP incident forensics, add and list incident notes, and fetch malware analysis reports. | | URL lists | List, create, update, patch, and delete URL lists, upload a list file, and deploy pending list changes to enforcement. | | SCIM users & groups | List, create, update, and delete SCIM users and groups - the access-management surface for provisioning workflows. | | URL lookup | Ask Netskope how it categorizes a set of URLs. | | Raw API access | A flexible "Netskope API request" action covering every endpoint in the curated REST API v2 surface. | The curated surface is a subset of the full [Netskope REST API v2](https://docs.netskope.com/en/rest-api-v2-overview-312207/); the tenant's built-in API documentation (Swagger) lists everything the platform exposes. ## Get your credentials Serval needs your **tenant hostname prefix** and a **REST API v2 token**. It's the part of your Netskope URL before `.goskope.com`: for `https://mycompany.goskope.com` the tenant is `mycompany` (regional tenants look like `mycompany.eu`). In your Netskope tenant, go to **Settings > Administration > Administrators & Roles > Administrators** and create a **Service Account**. Netskope issues the REST API v2 token when the service account is created. Netskope tokens are scoped per endpoint at creation. Grant, at minimum, read on `/api/v2/events/data/alert` (used by the connection health check), and add the endpoints your workflows will call: the other event and data-export endpoints for ingestion, `/api/v2/policy/urllist` (read-write) for list automation, the `/api/v2/scim/*` endpoints for user/group management, and the `/api/v2/incidents/*` endpoints for triage. If IP allowlisting is enabled on the tenant, add Serval's egress IPs to the Custom IP list (contact [support@serval.com](mailto:support@serval.com) for the list), or route the connection through a self-hosted worker. ## Connect Netskope to Serval In Serval, add a new connection and choose **Netskope** (shown with a Beta label). Enter only the hostname prefix - `mycompany` for `mycompany.goskope.com`. Values containing `.goskope.com`, a scheme like `https://`, or uppercase letters are rejected. Paste the REST API v2 token from the service account you created. Give the connection a name (for example `Production`) so multiple Netskope tenants stay distinguishable. Serval builds your tenant's address from the prefix and runs the health checks below to confirm it can reach the Netskope API with your token. When you edit an existing connection, the stored token appears masked. Leave it as is to keep the existing token; to rotate it, replace the masked value with the entire new token. ## Verifying the connection The Netskope connection ships with four health checks. They also run again automatically whenever you save changes to the connection's settings. * **Validate Netskope API connection** - reads one alert event from the last hour. On failure, verify the tenant hostname, that the token is valid, and that the token's scope includes `/api/v2/events/data/alert`. * **List URL lists** - confirms the token can read URL lists, and reports how many were found. * **List SCIM users** - confirms the token can read SCIM users. * **Read audit events** - confirms the token can read the admin audit trail. ## Gotchas and troubleshooting Enter only the prefix - `mycompany` for `mycompany.goskope.com`, or `mycompany.eu` for a regional tenant. Serval builds the full tenant address from it and only ever sends your token to your own goskope.com subdomain. A Netskope REST API v2 token only works for the endpoints selected when it was created. If some health checks pass while others fail - or workflows fail on specific endpoints with valid credentials - the token is missing that endpoint's scope. Edit the service account's token scope in the Netskope tenant, or create a new token and rotate it into the connection. If the tenant enforces IP allowlisting, requests from non-allowlisted addresses fail even with a valid token. Add Serval's egress IPs to the tenant's Custom IP list, or route the connection through a self-hosted worker. Creating or editing a URL list does not change enforcement by itself - pending changes take effect only after calling the deploy endpoint (`POST /api/v2/policy/urllist/deploy`). Workflows that mutate lists should end with a deploy step. The `/api/v2/scim/*` endpoints only work on tenants where Netskope's SCIM directory is in use. If the SCIM health check fails while others pass, the tenant may not have SCIM enabled - the rest of the integration works normally. Netskope appears with a Beta label in the Serval connect catalog. Functionality described on this page is available today, but the integration's surface may still evolve. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Netskope integration. # NetSuite Source: https://docs.serval.com/sections/integrations/netsuite Connect Serval to Oracle NetSuite to read and write ERP records, run queries, and call custom RESTlets on demand from workflows. ## About NetSuite NetSuite is Oracle's cloud ERP for financials, orders, inventory, and CRM. Serval connects to one NetSuite account per connection - the connection is named "NetSuite \[Account ID]" and keyed by your Account ID - and calls NetSuite's SuiteTalk REST Web Services and RESTlets on demand when your workflows run. There are no prebuilt helpers or shipped workflows; every call goes through Serval's generic NetSuite API request action. **Authentication:** OAuth 2.0 client credentials (certificate-based machine-to-machine, the default and recommended option) or token-based authentication (TBA / OAuth 1.0a) for existing setups. **Data sync:** On demand only. NetSuite data is read or written when a workflow step runs - there is no background sync or entity ingestion. ## What the NetSuite integration enables | Capability | Description | | - | - | | Records - read and write | Create, read, update, and delete NetSuite records (customers, vendors, transactions, custom records) from workflow steps. | | Any REST Web Services resource | Generic passthrough to anything your NetSuite account exposes over REST Web Services - including SuiteQL queries - subject to the scopes you request and the permissions of the connected role. | | Custom RESTlets | Call your account's custom RESTlet deployments with the same connection credentials. | | Connection health check | A built-in "Test NetSuite Connection" check verifies that authentication succeeds and REST Web Services are reachable. | Anything defined in the [NetSuite API](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/book_1559132836.html) can be accessed through Serval. ## Get your credentials Everything Serval needs is created inside NetSuite. Start with the prerequisites that apply to both authentication methods, then follow the tab for the method you plan to use. Oracle's official reference for REST Web Services is [here](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/book_1559132836.html). In NetSuite, go to **Setup → Company → Company Information** and copy the Account ID. Sandbox accounts use the underscore form, such as 1234567\_SB1. Go to **Setup → Company → Enable Features → SuiteCloud** and enable SuiteTalk REST Web Services. Go to **Setup → Integration → Manage Integrations → New** and create (or pick) the integration record Serval will use. Enable OAuth 2.0 on the integration record and copy the **Client ID**. Go to **Setup → Integration → OAuth 2.0 Client Credentials (M2M) Setup**, pick the integration and role, upload your public certificate, and copy the generated **Certificate ID**. Keep the PEM private key that matches the uploaded certificate - you will paste it into Serval, including the BEGIN and END lines. The signing algorithm you pick in Serval must match the key and certificate pair you uploaded to NetSuite. RSA-PSS (PS256, the default) and ECDSA algorithms are supported - plain RS256 is not. Enable token-based authentication on the integration record and capture the **Consumer Key** and **Consumer Secret**. Use **Manage Access Tokens** to create an access token for the integration, user, and role Serval should act as, and capture the **Token ID** and **Token Secret**. NetSuite shows the consumer secret and token secret only once, at creation. If you lose them, you must create a new token or integration record. ## Connect in Serval Fill in **NetSuite Account ID** (required) - the placeholder shows "1234567 or 1234567\_SB1". Use the ID from Setup → Company → Company Information, in its native form (underscores for sandboxes). Leaving it (or any required field) blank is flagged in the form with "This field is required", and the ID may only contain letters, numbers, underscores, and hyphens - anything else is rejected on save with "account ID can only contain letters, numbers, underscores, and hyphens". **Authentication method** defaults to "OAuth 2.0 client credentials (service account)"; "Token-based authentication (OAuth 1.0/TBA)" is available for existing TBA setups. If a configuration reaches Serval with no method recorded but with any token-based credential filled in, Serval infers token-based authentication. An unrecognized value is rejected with "unsupported authentication method "\[value]"". For OAuth 2.0 client credentials: **Client ID** (required), **Certificate ID** (required - the certificate ID generated on NetSuite's M2M setup page), **Signing Algorithm** (optional select, default "PS256 (RSA-PSS SHA-256)"; also PS384, PS512, ES256, ES384, ES512), **Private Key** (required multiline secret field - paste the PEM key including the BEGIN and END lines; a missing key is rejected on save with "private key is required for OAuth 2.0 client credentials"), and **OAuth 2.0 Scopes** (required, pre-filled with rest\_webservices; the form suggests rest\_webservices, restlets, and suite\_analytics as common values, and at least one scope must remain in the list). For token-based authentication: **Consumer Key**, **Consumer Secret**, **Token ID**, and **Token Secret** are all required. These are secret fields, so a missing one is reported on save with a matching message - for example "consumer key is required for token-based authentication" and "token secret is required for token-based authentication". Click **Submit** to create the connection, named "NetSuite \[Account ID]". Any validation failure is reported as "Invalid NetSuite configuration" followed by the specific cause. When editing an existing connection, saved secrets appear masked - bullets with only the last four characters visible - alongside a **Replace** button. Leave a masked secret as-is (or any field blank) to keep the stored value - only the fields you fill in are replaced. ## Verifying the connection Serval ships one health check for NetSuite: **Test NetSuite Connection** - verifies that NetSuite authentication succeeds and REST Web Services are reachable by reading NetSuite's record metadata catalog with your configured credentials. * On success: "Successfully authenticated with NetSuite and reached REST Web Services." * On failure: "Unable to connect to NetSuite. Verify the account ID, selected authentication method, credentials, and REST Web Services permissions." A green test only proves REST Web Services access. RESTlet calls additionally need the restlets scope (OAuth 2.0) granted both in Serval and to the NetSuite integration record - and SuiteQL queries, which run through REST Web Services, depend on the connected role's permissions. For token-based authentication, permissions follow the token's user and role. ## Gotchas and troubleshooting Serval automatically lowercases your Account ID and converts underscores to hyphens to build the NetSuite API address - 1234567\_SB1 becomes 1234567-sb1. Enter the ID exactly as NetSuite shows it (underscores for sandboxes, such as 1234567\_SB1). For token-based authentication, the ID is also used as the realm exactly as you entered it, so don't hand-convert it yourself. The consumer secret and token secret are displayed by NetSuite a single time, at creation. Capture both immediately; if they're lost, create a new access token or integration record and update the Serval connection. Only PS256, PS384, PS512 (RSA-PSS) and ES256, ES384, ES512 (ECDSA) signing algorithms are accepted, matching NetSuite's machine-to-machine requirements. The default is PS256. Anything else is rejected with "unsupported OAuth 2.0 signing algorithm "\[value]"", and the algorithm must match the key type of the certificate uploaded to NetSuite. Serval requests the scopes you list (rest\_webservices is pre-filled). REST Web Services calls - including SuiteQL queries - are covered by rest\_webservices; calling RESTlets requires the restlets scope; suite\_analytics is the other common value the form suggests. Whatever you request, the NetSuite integration record and role must actually be granted the matching access. Under token-based authentication there are no scopes; permissions follow the token's user and role. Serval fetches a fresh access token for every request, so a misconfigured certificate or key fails when a workflow (or the health check) runs - with errors like "failed to decode PEM private key", "failed to parse PEM private key", "PEM private key must be RSA or ECDSA", or "NetSuite token request failed with status \[number]" followed by NetSuite's response. Run the health check right after saving to catch these early. Updates merge field by field: blank fields keep their existing values and masked secrets keep the stored secret. When switching methods, explicitly fill in every field the new method requires - the previous method's saved values remain stored but are no longer used. All validation failures on create or update are reported as "Invalid NetSuite configuration" followed by the specific cause - for example "consumer key is required for token-based authentication". Read the attached message to find the exact field to fix. (Blank required fields are flagged inline in the form with "This field is required" before anything is sent.) This integration ships no prebuilt workflows, typed endpoints, or entity ingestion. Everything runs through the generic NetSuite API request action against your account's REST Web Services and RESTlet hosts, so workflow authors describe the NetSuite resource they want to reach. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your NetSuite integration. # NinjaOne Source: https://docs.serval.com/sections/integrations/ninjaone Connect NinjaOne (formerly NinjaRMM) to Serval so workflows can manage devices, patches, alerts, tickets, and IT documentation through the full NinjaOne Public API v2. ## About NinjaOne NinjaOne (formerly NinjaRMM) is a remote monitoring and management (RMM) platform for managing endpoints, patching, alerts, and IT documentation. Serval connects to your NinjaOne tenant using an OAuth 2.0 client credentials app that you create in the NinjaOne admin console, and gives Serval workflows typed access to the full NinjaOne Public API v2 - more than 300 endpoints. The integration is region-aware: you pick your NinjaOne cloud instance (US, US2, EU, CA, or Oceania) when you connect, and all traffic goes to that instance. There are no prebuilt installable workflows; this is a pure API integration with four built-in health checks. **Authentication:** OAuth 2.0 client credentials, via an "API Services (machine-to-machine)" client app created in NinjaOne. **Data sync:** On-demand only. There is no background or scheduled sync - workflow runs call the NinjaOne API live using your stored credentials, and four built-in health checks verify the connection. ## What the NinjaOne integration enables | Capability | Description | | - | - | | Device management | List, search, and inspect managed devices; reboot devices, set owners, approve or reject devices, schedule maintenance, and decommission devices. | | Patch management | Scan for and apply OS and third-party software patches on a device, and report on patch installs. | | Scripting and automation | List automation scripts, look up per-device scripting options, run scripts on a device, and configure and control Windows services. | | Alerts and activities | List and reset alerts, and read activity logs globally or per device. | | Organizations and locations | Create and manage organizations, locations, and policies; generate agent installers; read org-level devices, end users, and custom fields. | | Reporting queries | Fleet-wide reports covering antivirus status and threats, device health, software inventory, OS and software patches, logged-on users, disks, volumes, processors, RAID, network interfaces, backup usage, and Windows services. | | Ticketing | Create and update NinjaOne tickets, add comments, read log entries, and manage ticket forms, boards, statuses, and attributes. | | Knowledge base and IT documentation | Manage knowledge base articles and folders, document templates, organization documents, and checklists. | | Custom fields | Read and update custom fields at the device, organization, and location level, including bulk operations and attachment handling. | | Users and roles | List users, end users, and technicians; manage user roles and role membership. | | ITAM and software licenses | Manage unmanaged devices, asset relationships, tags, software products, and software license records with assignments. | | Backup, billing, vulnerabilities, and webhooks | Read backup jobs and integrity checks, manage billing entities such as invoices, products, and agreements, manage vulnerability scan groups, and configure the account webhook. | Anything defined in the [NinjaOne API](https://app.ninjarmm.com/apidocs/) can be accessed through Serval. ## Get your credentials Serval authenticates with a machine-to-machine API client app in NinjaOne. You will need the app's Client ID, its Client Secret, and the region your NinjaOne tenant is hosted in. NinjaOne's official guide is [How to Set Up API OAuth Token](https://www.ninjaone.com/docs/integrations/how-to-set-up-api-oauth-token/); the short version follows. In NinjaOne, go to **Administration > Apps > API**. Open the **Client App IDs** tab and click **Add**. Set **Application platform** to **API Services (machine-to-machine)**. No redirect URI is needed for this platform type. Give the app a recognizable name (for example "Serval"). The name appears in NinjaOne's OAuth token management area. Select the **Monitoring** and **Management** scopes. Serval requests exactly these two scopes, so both must be allowed on the app. The **Control** scope is not requested by Serval and can be left off. Ensure **Client Credentials** is the allowed grant type. Click **Save**, then copy the generated **Client ID** and **Client Secret**. Check which NinjaOne cloud instance hosts your tenant - it is the domain in your browser: app.ninjarmm.com, us2.ninjarmm.com, eu.ninjarmm.com, ca.ninjarmm.com, or oc.ninjarmm.com. You will pick the matching API Region in Serval. The Client Secret is shown only once, when the app is created. If you lose it, regenerate it in NinjaOne. For more detail on scopes and grant types, see NinjaOne's [API OAuth Token Configuration](https://www.ninjaone.com/docs/application-programming-interface-api/oauth-token-configuration/) reference. ## Connect in Serval All three fields on the connect form are required - each label ends with an asterisk. Start a new NinjaOne connection from Serval's integrations area. **API Region** is a dropdown, pre-filled with "US (app.ninjarmm.com)". The options are "US (app.ninjarmm.com)", "US2 (us2.ninjarmm.com)", "EU (eu.ninjarmm.com)", "CA (ca.ninjarmm.com)", and "Oceania (oc.ninjarmm.com)". The text beneath the field reads "Select the NinjaOne region your tenant is hosted in" - pick the one matching the domain you noted in NinjaOne. **Client ID** is a plain text field described as "Your NinjaOne API application Client ID". Paste the Client ID from your NinjaOne client app. **Client Secret** is a password field described as "Your NinjaOne API application Client Secret". Paste the complete Client Secret you copied when creating the app. Click **Connect NinjaOne** (the button reads **Submit** if you are using the configure dialog). Serval then automatically runs the connection's health checks - any checks you have disabled are skipped - see the next section. When you edit an existing NinjaOne connection, the saved Client Secret appears masked: a row of bullet characters with the last 4 characters visible. Use the edit control next to it (the pencil icon on the connection settings page, or the **Replace** button in the configure dialog) to enter a new value. Any time you save changes to the connection - including unrelated edits or a credential rotation - re-enter the complete Client Secret, and confirm the API Region and Client ID are still correct before saving. Do not clear pre-filled fields you intend to keep, and do not assume the masked value carries over on its own. ## Verifying the connection Serval runs four health checks automatically after a successful connect (skipping any you have disabled), and you can re-run them on demand from the connection's health check section. * **Test NinjaOne Connection** - verifies the stored credentials can authenticate against the NinjaOne API. Success: "Successfully authenticated with NinjaOne". Failure: "Unable to connect to NinjaOne. Please verify your Client ID, Client Secret, API region, and OAuth scopes are correct." * **List NinjaOne Organizations** - confirms the integration can list organizations (requires the "monitoring" scope). Success: "Successfully listed organizations from NinjaOne (sample size: \[number])". Failure: "Unable to list organizations from NinjaOne. Please verify the API credentials have the 'monitoring' scope." * **List NinjaOne Devices** - confirms the integration can list managed devices (requires the "monitoring" scope). Success: "Successfully listed devices from NinjaOne (sample size: \[number])". Failure: "Unable to list devices from NinjaOne. Please verify the API credentials have the 'monitoring' scope." * **List NinjaOne Users** - confirms the integration can list users (requires the "monitoring" scope). Success: "Successfully listed users from NinjaOne (sample size: \[number])". Failure: "Unable to list users from NinjaOne. Please verify the API credentials have the 'monitoring' scope." All four health checks are read operations, so they exercise only the Monitoring scope. Write actions in workflows (creating tickets, applying patches, updating custom fields) also rely on the Management scope, which Serval requests at connect time - if reads work but writes are denied, check the app's scopes in NinjaOne. ## Gotchas and troubleshooting The selected region is used for both sign-in and all API traffic, and Serval only talks to the five official NinjaOne hosts (app.ninjarmm.com, us2.ninjarmm.com, eu.ninjarmm.com, ca.ninjarmm.com, and oc.ninjarmm.com). If the region does not match the cloud instance hosting your tenant, authentication fails and the "Test NinjaOne Connection" health check reports it. The region also becomes the connection's instance label in Serval, so picking the right one keeps the connection easy to identify. The connect form only asks for API Region, Client ID, and Client Secret. Serval always requests the Monitoring and Management scopes, so your NinjaOne client app must allow both or the connection fails to authenticate. The Control scope (used by NinjaOne for remote-access features) is never requested by Serval, and none of the API operations Serval exposes require it. Whenever you save changes to an existing NinjaOne connection, replace the masked Client Secret with the full secret again, even if you are only changing something else. Also verify the API Region and Client ID before saving, and never clear a pre-filled field you mean to keep. If a connection stops working right after an edit, re-enter the complete credentials and save again. Serval uses the OAuth client credentials grant only. NinjaOne client apps created with the Authorization Code or Implicit grant platforms will not work, and no redirect URI is involved. Remember that NinjaOne shows the Client Secret only once at creation time - if it was not saved, regenerate it. Every health check is a read that needs only the Monitoring scope - none of them exercise writes. If ticket creation, patch deployment, or custom field updates fail in workflows while all four checks are green, confirm the NinjaOne client app still allows the Management scope under **Administration > Apps > API**, then re-save the connection in Serval (re-entering the complete Client Secret) so it authenticates fresh. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your NinjaOne integration. # Notion Source: https://docs.serval.com/sections/integrations/notion Connect your Notion workspace to Serval to power workflow automation and sync your shared pages and databases into Serval's knowledge base. ## About Notion Serval's Notion integration connects a Notion workspace to Serval so workflows can search and read your Notion content, and so pages and databases shared with the integration can be ingested into Serval's knowledge base. Serval stores your credentials securely and attaches them to every call on your behalf - all traffic goes only to Notion's official API host (`api.notion.com`). The integration also installs one ready-to-use workflow, **Search and Read Notion Pages**, which finds relevant pages and reads their full content so it can be used to answer questions. **Authentication:** Serval-managed OAuth (recommended), a bring-your-own Notion public integration, or a Notion internal integration secret (API key). All three behave identically once connected. **Data sync:** Background knowledge sync of every page and database shared with the integration. After the first full sync, items are only re-synced when they have been edited in Notion (or when a previous sync attempt didn't complete). You can also trigger a manual sync from the Serval UI at any time. ## What the Notion integration enables | Capability | Description | | - | - | | Workflow API access | Serval workflows can call any Notion API operation through Serval's built-in Notion action, with your credentials injected automatically. | | Knowledge sync | Pages and databases - including database rows that Notion's own search misses - are ingested into Serval's knowledge base as Markdown, with parent-child relationships preserved and incremental re-sync when content changes. Accepting a [knowledge suggestion](/sections/documentation/suggestions/overview) also creates or updates pages in Notion. | | Seeded workflow: Search and Read Notion Pages | Installed automatically with the integration and runs without requiring approval. It searches for pages matching the request - most recently edited first - then reads their content: paragraphs, headings, lists, to-dos, toggles, tables, code, callouts, and more - so the answers come from the actual page text. | | Health checks | Three built-in checks verify connectivity, workspace user listing, and content visibility. See [Verifying the connection](#verifying-the-connection). | Anything defined in the [Notion API](https://developers.notion.com/reference/intro) can be accessed through Serval. ## Get your credentials What you need depends on which connect option you choose. All Notion integrations are created and managed from the [Notion integrations dashboard](https://www.notion.so/profile/integrations). Nothing to create. You'll sign in to Notion in a popup, choose a workspace, and pick which pages to share - Serval handles everything else. Skip ahead to [Connect in Serval](#connect-in-serval). Open the [Notion integrations dashboard](https://www.notion.so/profile/integrations) and click **New integration**. Set the type to **Internal** and enable the **Read content** capability. On the integration's settings page, go to **Configuration → Internal Integration Secret** and copy the secret (it starts with `ntn_`, or `secret_` for older integrations). In Notion, open each page or database Serval should read and use **••• → Connections** to connect your integration. Child pages inherit the connection automatically. The integration needs the **Read content** capability and must be connected to at least one page before Serval can read anything. Serval validates the secret itself when you connect - an invalid secret is rejected immediately - but it cannot check page sharing for you: with nothing shared, the connection succeeds and syncs and searches simply come back empty. Open the [Notion integrations dashboard](https://www.notion.so/profile/integrations) and click **New integration**, or open an existing public integration. Set the integration type to **Public** - only public Notion integrations support OAuth. Copy the **Redirect URI** shown in Serval's connect modal and paste it into the integration's **Redirect URIs** list in Notion, then save. Notion requires an exact, character-for-character match. From the **OAuth Domain & URIs** section of the integration's settings page, copy the **OAuth client ID** and the **OAuth client secret** (click **Show** next to the secret). If you have an *internal* Notion integration, use the API-key path instead - it ends up with the same access and behaves identically at runtime. ## Connect in Serval Open the Notion integration in Serval and pick one of the three options in the connect modal. Select **Sign in with Notion (OAuth)**. Sign in to Notion, choose the workspace to connect, and pick the pages to share with Serval. There is no permissions screen to review - Notion OAuth has no scopes; access is governed entirely by which workspace you select and which pages you share. The connection is named after your Notion workspace, with your email in parentheses when Notion provides it - for example, a workspace called Acme connected by [jane@acme.com](mailto:jane@acme.com) appears as Acme ([jane@acme.com](mailto:jane@acme.com)). If a teammate connects the same workspace, they get their own separate connection; this is expected. Select **Use your own Notion integration**. The modal shows a read-only **Redirect URI** field with a **Copy** button - copy it into your Notion integration's Redirect URIs list and save *before* continuing. Always copy rather than type; Notion rejects anything that isn't an exact match. * **Display name** (optional) - a friendly name shown in Serval, e.g. "My Company Notion". You choose this. * **OAuth client ID** (required) - found in the OAuth Domain & URIs section of your Notion integration's settings page. * **OAuth client secret** (required) - a password field, placeholder `secret_...`. Click **Show** next to the secret in Notion to reveal it before copying. The **Connect** button stays disabled until both required fields are filled in. Click **Connect** and complete the Notion authorization as the installing user, choosing the workspace. Your submitted credentials are held for only **10 minutes** - if the Notion step takes longer, the connection fails with "Invalid or expired OAuth state" and you must re-submit the form. When reconnecting, the **Display name** and **OAuth client ID** are pre-filled, but the **OAuth client secret** is never pre-filled - you must re-enter it every time. Select **Use an internal integration secret (API key)**. Enter your secret in the **Internal Integration Secret** field - a password field with placeholder `ntn_...`. The **Connect** button stays disabled until you've entered a value. Click **Connect**. Serval validates the secret live against Notion (up to 15 seconds) *before* saving anything. If the secret is invalid, or isn't actually an internal integration secret (for example, a pasted user OAuth token), the connection fails immediately with: "Could not verify this Notion secret. Make sure it's a valid Internal Integration Secret with read content access, and that the integration is connected to at least one page." The connection's identity is tied to the integration's bot user, so rotating the secret later updates the same connection rather than creating a duplicate. When rotating, paste the **complete** new secret - Serval re-validates whatever you submit and never falls back to the stored secret, so a blank field fails with "A Notion internal integration secret is required." and a masked value fails verification. A blank field does **not** keep the old secret. ## Verifying the connection After connecting, run the integration's health checks: * **Test Notion Connection** - verifies basic connectivity and authentication by fetching the integration's bot user. * Success: "Successfully connected to Notion as "\[name]"" (the name falls back to "Unknown" when Notion returns no name) * Failure: "Unable to connect to Notion. Please verify your integration token and permissions are correct." * **List Notion Users** - verifies the integration can list users in the workspace. * Success: "Successfully listed users from Notion (found \[number])" * Failure: "Unable to list users from Notion. Please verify your integration has access to the workspace." * **Search Notion Content** - verifies the integration can search pages and databases. * Success: "Successfully searched Notion content (found \[number] items)" - with ", more available" appended inside the parentheses when more results exist * Failure: "Unable to search content in Notion. Please verify your integration has access to pages and databases." The most common "all checks green but nothing syncs" cause: **Search Notion Content** succeeds even when it finds **zero** items. Read the count in the success message - "found 0 items" means authentication works but no content has been shared with the integration yet. ## Gotchas and troubleshooting This is the #1 source of Notion confusion. Every read path - knowledge sync, the **Search Notion Content** health check, and the seeded search workflow - sees only pages and databases connected to the integration. There is no workspace-wide crawl. A successful connect with nothing shared yields an empty knowledge sync and "Successfully searched Notion content (found 0 items)". Share content in Notion via **••• → Connections** on each top-level page or database; child pages inherit the connection. (Adding a connection to a page requires edit access on that page - that's Notion's rule, not Serval's.) For the OAuth path, the page picker on Notion's authorize screen controls the initial grant. **Search Notion Content** reports success regardless of how many items it finds. The found-count in the message is the real signal - "found 0 items" means the credentials work but nothing is shared with the integration yet. On a knowledge source's first sync, Serval deliberately waits 30 seconds for Notion's search indexing before searching. Pages newly shared with the integration can also take time to appear in Notion's search index, so a sync triggered immediately after sharing may miss them - re-sync if a just-shared page is absent. Serval verifies the pasted secret against Notion before saving anything. An invalid secret - or any token that isn't a real internal integration secret (for example, a pasted user OAuth token) - fails immediately with: "Could not verify this Notion secret. Make sure it's a valid Internal Integration Secret with read content access, and that the integration is connected to at least one page." Note that this check validates the secret itself; it cannot tell whether any pages have actually been shared with the integration yet. When rotating the Internal Integration Secret, Serval re-validates whatever you submit and never falls back to the stored value - a blank field fails with "A Notion internal integration secret is required." and a masked value fails verification. Paste the complete new secret. Similarly, reconnecting a bring-your-own integration pre-fills only the Display name and OAuth client ID - the OAuth client secret must be re-entered every time. Notion rejects any redirect URI that doesn't exactly match a registered one. Always copy the URI from Serval's connect modal rather than typing it. Your submitted client ID and secret are held for only 10 minutes - if the Notion authorize step takes longer, the connection fails with "Invalid or expired OAuth state" and you must re-submit the form. Only *public* Notion integrations support OAuth. If you have an internal integration, use the API-key path instead - both end up with the same access and behave identically at runtime. The OAuth flow requests no scopes and Notion returns none. Access is controlled entirely by which workspace you select at authorize time, plus per-page sharing afterwards. OAuth and bring-your-own connections are identified by workspace *and* the connecting user's email, and named after the workspace with the connecting user's email in parentheses. Two teammates connecting the same Notion workspace create two distinct connections. This is expected behavior, not a duplicate-connection bug. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Notion integration. # Nozomi Networks Source: https://docs.serval.com/sections/integrations/nozomi Connect Nozomi Networks OT and IoT security monitoring to Serval with an API key so workflows can read alerts, asset inventory, vulnerabilities, and sensor health from Guardian, CMC, or Vantage. Currently in beta. ## About Nozomi Networks Nozomi Networks is an operational technology (OT) and Internet of Things (IoT) security monitoring platform. It watches industrial and connected devices, raises alerts on suspicious or risky activity, keeps an inventory of the assets it sees, and reports on their vulnerabilities. Serval connects to your Nozomi deployment with an API key so workflows can read this security data and act on it. The Nozomi Networks integration is currently in **beta**. Nozomi ships in two forms, and each connection points at one of them: * **Guardian / CMC (on-premises).** Guardian appliances (and the Central Management Console, CMC, that aggregates them) run inside your own network. A connection points at the appliance's own URL. * **Vantage (cloud).** Vantage is Nozomi's cloud platform, reached at your tenant's `vantage.nozominetworks.io` address. A connection is tied to the product you pick when you create it. You can't switch an existing connection between Guardian/CMC and Vantage, because that would repoint every workflow using it at a different system. To move to the other product, create a new Nozomi Networks connection. **Authentication** Serval authenticates with an API key created in Nozomi for a dedicated service user: a key name and a key token. On Guardian and CMC this is an OpenAPI key; on Vantage it's an API key. Serval stores the token encrypted and exchanges it for a short-lived session each time it calls Nozomi, so the workflows you build never handle the key directly. The service user's permissions in Nozomi determine what Serval can read. **Data sync** On demand only. Serval calls Nozomi at the moment a workflow step runs. There is no background sync, and the integration ships no pre-installed workflows. ## What the Nozomi integration enables The capabilities available depend on which product the connection points at. **Guardian and CMC** | Capability | Description | | - | - | | Alerts | List and read alerts, follow an alert to its supporting detail, and acknowledge or close alerts. | | Asset inventory | Query the assets Guardian has discovered on the monitored network. | | Ad hoc queries | Run Nozomi's own query language to pull tailored views of alerts, assets, and other monitored data. | | Network captures | Work with recorded network traffic and packet captures for investigation. | | Users and groups | Read and manage the appliance's own users and user groups. | | Reports | Generate reports and work with report templates. | | Quarantine | Read and manage quarantined items. | | Threat intelligence | Read the appliance's threat intelligence data. | | Sensor health | Read sensor resource and license information (reading sensor resources requires a service user with the admin role or the health permission). | **Vantage** | Capability | Description | | - | - | | Alerts | List and read alerts across the tenant. | | Assets and sites | Read the asset inventory and the sites assets are grouped into. | | Vulnerabilities | Read the vulnerabilities Vantage has identified. | | Sensors | List the sensors connected to the tenant. | | Wireless networks | Read discovered wireless networks. | ## Get your credentials You create an API key in Nozomi for a dedicated service user, and give Serval the key's name and token. The service user's permissions decide what Serval can read, so grant it the access your workflows need. In Nozomi, create (or choose) a service user for Serval and give it the permissions your workflows require. On Guardian or CMC, include the admin role or the health permission if you plan to read sensor resource metrics. Generate a key for that user: an OpenAPI key on Guardian or CMC, or an API key on Vantage. Note the key name. Copy the token shown when the key is generated and store it somewhere safe. It's shown only once. For Guardian or CMC, use your appliance's URL (for example `https://guardian.example.com`). For Vantage, use your tenant URL (for example `https://company.customers.us1.vantage.nozominetworks.io`). For Guardian and CMC, the appliance runs inside your own network, so its URL must be reachable from Serval. If Serval can't reach the appliance, the connection can't sign in. ## Connect in Serval Open your team workspace, go to **Integrations → Connect new**, choose **Nozomi Networks**, and fill in the connect form. Select **Guardian / CMC (on-premises)** or **Vantage (cloud)**. The URL field changes to match your choice. Remember that this can't be changed later. For Guardian or CMC, enter the appliance URL. For Vantage, enter your tenant URL, which must be a `vantage.nozominetworks.io` address. Enter the name of the OpenAPI key (Guardian or CMC) or API key (Vantage) you created for the service user. Paste the key token. Serval stores it encrypted and only uses it to obtain the short-lived sessions it needs to call Nozomi. Submit to create the connection, then run the health checks below to confirm everything works. When you edit an existing connection, leaving the Key Name or Key Token blank keeps the stored value, so you can update one without re-entering the other. The Product can't be changed on edit. ## Verifying the connection When you connect, Serval confirms it can authenticate with the appliance or tenant. The integration also includes four built-in health checks you can run at any time from the connection's **API Integration** tab: | Check | What it verifies | | - | - | | Test Connection | Confirms Serval can authenticate with the configured Guardian/CMC appliance or Vantage tenant. | | List Alerts | Confirms the service user can read alerts. | | List Assets | Confirms the service user can read the asset inventory. | | Check Sensor Health | Reads sensor health: resource metrics on Guardian/CMC, or the connected-sensor list on Vantage. On Guardian/CMC this requires the service user to have the admin role or the health permission. | If Test Connection passes but a specific check fails, the service user is reachable but lacks permission for that area in Nozomi. The most common example is Check Sensor Health on Guardian/CMC, which needs the admin role or the health permission. Widen the service user's permissions and rerun the check. ## Gotchas and troubleshooting A connection is fixed to Guardian/CMC or Vantage from the moment you create it, because each product exposes a different set of capabilities and workflows are built against one of them. To use the other product, create a separate Nozomi Networks connection. On-premises appliances live inside your network. If Serval can't reach the appliance URL, sign-in fails. Confirm the URL is correct and that network access from Serval to the appliance is allowed. A Vantage connection must point at a `vantage.nozominetworks.io` address (for example `https://company.customers.us1.vantage.nozominetworks.io`). A different host is rejected when you save. Everything Serval reads is bounded by the permissions of the service user whose key you configured. If a workflow gets a permission error while the connection looks healthy, widen that user's access in Nozomi. The Nozomi Networks integration is marked beta in the connect screen. Behavior and available capabilities may change. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Nozomi Networks integration. # Obsidian Security Source: https://docs.serval.com/sections/integrations/obsidian-security Obsidian Security is a SaaS security posture management (SSPM) platform - connect it to Serval so workflows can read intelligence alerts, accounts, connected services, activity events, and posture and compliance data, and update alerts as part of triage automation. ## About Obsidian Security Obsidian Security is a SaaS security posture management (SSPM) platform that monitors your connected cloud applications, generates security intelligence alerts, and tracks posture and compliance state. Connecting it to Serval lets workflows read intelligence alerts, query accounts and entities, list connected services, search activity events, read posture and compliance data, and perform write operations such as updating alert status. **Authentication:** API token (bearer). You pick the regional API endpoint that matches your Obsidian Security tenant and paste an API access token created in Obsidian Security. Serval stores the token server-side and attaches it to requests for you - it is never exposed to workflow code, and it is only ever sent to Obsidian's own regional API domains. **Data sync:** On demand. There is no background sync or scheduled ingestion - workflows, actions, and health checks call the Obsidian Security API at the moment they run, and nothing is pulled into Serval on a schedule. ## What the Obsidian Security integration enables | Capability | Description | | - | - | | Obsidian Security API access | The built-in "Obsidian Security API request" action sends any query supported by Obsidian's GraphQL API to your tenant's regional endpoint, for both reads and writes. | | Intelligence alerts | Read security intelligence alerts (including id, ticket id, name, and severity, ordered by generation time) and automate triage with updates to alert status, state, resolution tags, and alert comments. | | Accounts and entities | Query the entity catalog - accounts, entities, and aggregate views - across all the services connected to Obsidian. | | Connected services | List the cloud services your organization has connected to Obsidian Security. | | Activity events | Search the collected activity event stream, fetch individual events, and run event aggregations. | | Posture and compliance | Read and manage posture rules and settings, plus compliance standards, controls, mappings, and reports (including create, update, and clone operations). | | Health checks | Four built-in health checks validate the connection and the token's read access to connected services, accounts, and intelligence alerts. | Anything defined in the [Obsidian Security API](https://docs.obsidiansecurity.com/obsidian/api/graphql) can be accessed through Serval. ## Get your credentials Serval connects with an API access token created in your Obsidian Security tenant, plus the regional API endpoint your tenant is hosted on. Obsidian documents token creation in its [API Access Tokens guide](https://docs.obsidiansecurity.com/obsidian/settings/api-access-tokens). Log in to your Obsidian Security tenant and navigate to **Settings**, then **API Access Tokens**. Create a new token and give it a descriptive name such as "Serval Integration". Grant read access to the data your Serval workflows will use - at minimum connected services, accounts/entities, and intelligence (alerts), which is what the shipped health checks exercise. Add read or write access for anything else your workflows touch (activity events, posture, compliance). Workflows that read data outside the token's scope fail at runtime with a permission error. Copy the token right away and keep it somewhere safe until you've pasted it into Serval. Check whether your tenant is hosted in the US, EU, or AU - see Obsidian's [server endpoints documentation](https://docs.obsidiansecurity.com/obsidian/api/rest#server-endpoints). You'll select the matching region in Serval. Obsidian shows the full token only once, at creation time. If you lose it, you must generate a new one. Tokens are tenant-bound: a token created in one region's tenant will not authenticate against another region's endpoint. ## Connect in Serval "Select the regional API endpoint that matches your Obsidian Security tenant." A dropdown with exactly three options - **US (api.obsec.io)**, **EU (api.obsec.eu)**, and **AU (api.sy.obsec.io)** - defaulting to US. Pick the region you confirmed in the previous section. "Bearer token generated in Obsidian Security under Settings -> API Access Tokens." Paste the token you copied. There is no format check on this field - the token's validity is proven by the health checks after you save. Once saved, it displays masked (bullet characters plus the last 4 characters). Save the connection, then run the health checks below to confirm everything works. If saving fails, the error appears as "Failed to install integration: \[reason]" (or "Failed to update integration: \[reason]" when editing). Editing the connection later: the saved token displays masked and only changes when you type a new value - leaving the masked value untouched, or clearing the token field to blank, keeps your stored token, so you can safely change the Region without retyping it. That said, because tokens are tenant-bound, changing the Region generally means you need a new token from that region's tenant anyway. ## Verifying the connection The Obsidian Security integration ships four health checks: **Validate Obsidian Security API connection** - verifies the configured token can reach the Obsidian Security API by querying the API version. * Success: "Successfully connected to Obsidian Security API." * Failure: "Unable to connect to the Obsidian Security API. Verify that the API token is valid and the selected region matches your tenant." **List connected services in Obsidian Security** - verifies the token can list the cloud services your organization has connected to Obsidian. * Success: "Successfully retrieved \[number] connected service(s) from Obsidian Security." * Failure: "Unable to list connected services. Verify the API token has read access to the Obsidian Security service catalog." **List accounts in Obsidian Security** - verifies the token can read the entity/accounts catalog by fetching a single account. * Success: "Successfully read accounts from Obsidian Security (returned \[number] record(s))." * Failure: "Unable to read accounts from Obsidian Security. The API token may lack permission to query the entity catalog." **List intelligence alerts in Obsidian Security** - verifies the token can read security intelligence by fetching the most recent alert. * Success: "Successfully read intelligence from Obsidian Security (returned \[number] alert(s))." * Failure: "Unable to read intelligence alerts. The API token may lack permission to query intelligence, or no alerts exist yet." If "Validate Obsidian Security API connection" passes but one of the list checks fails, your token and region are fine - the token just lacks read access to that data. Edit the token's permissions in Obsidian Security under **Settings**, then **API Access Tokens**, granting read access to connected services, accounts/entities, and intelligence. ## Gotchas and troubleshooting The connection check only proves the token is valid for your region. Each kind of data (intelligence, accounts/entities, connected services, events, posture, compliance) needs its own read access on the token. A workflow that touches data outside the token's scope fails at runtime with a permission error - broaden the token's access in Obsidian Security and re-run. Serval accepts exactly three regional domains: api.obsec.io (US), api.obsec.eu (EU), and api.sy.obsec.io (AU). The connect form's dropdown only offers those three values, so you can't mistype one in the UI - but a connection created programmatically must pass exactly one of those lowercase host values. Anything else - including a value with an https\:// prefix or uppercase letters - is rejected with the error 'unsupported Obsidian Security API domain "\[value]"; must be one of api.obsec.io (US), api.obsec.eu (EU), or api.sy.obsec.io (AU)'. And because tokens are tenant-bound, switching the Region usually means generating a new token in that region's tenant too. "Unable to read intelligence alerts. The API token may lack permission to query intelligence, or no alerts exist yet." has two possible causes - a missing token permission, or simply that your tenant has not generated any alerts yet. On a fresh tenant with no alerts, this failure is not necessarily a credentials problem. Obsidian Security exposes a single GraphQL API rather than a catalog of individual REST endpoints, so Serval ships no enumerated endpoint list for this integration. Workflows reach everything through the generic "Obsidian Security API request" action. If the API accepts a request but reports problems, the action fails with "Obsidian Security GraphQL request returned errors:" followed by each error message the API returned, joined by semicolons. The connection is labeled by the selected regional domain (for example, api.obsec.io). If you maintain multiple Obsidian Security connections, they are distinguished by region - not by a tenant name you choose. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Obsidian Security integration. # Okta Source: https://docs.serval.com/sections/integrations/okta Okta is a cloud identity and access management platform; Serval connects to it to read and manage users, groups, and applications, run access reviews, and automate identity lifecycle tasks. ## About Okta Okta is a cloud identity and access management (IAM) platform for managing users, groups, and application access. Serval connects to Okta using OAuth 2.0 client credentials against an Okta API Services app. Once connected, Serval can reach any Okta Management API capability - reading and managing users, groups, and applications, running access reviews, and automating identity lifecycle tasks. Serval also continuously brings your Okta directory into Serval in the background so users, groups, and applications stay up to date. **Authentication:** OAuth 2.0 client credentials. The Serval integration from the Okta Integration Network (OIN) uses the Client ID and Client Secret generated during installation. A custom Okta API Services app must use a private key JWT (`private_key_jwt`). **Data sync:** On-demand access to the full Okta Management API from workflows, plus a built-in background directory sync of users, groups (with members), and applications (with their assigned groups). Optionally, [Okta event hooks](#real-time-sync-with-event-hooks) push user and group changes to Serval in real time. ## What the Okta integration enables | Capability | Description | | - | - | | Full Okta Management API access | Any Okta Management API capability can be used from a workflow, with automatic retries on transient errors, pagination handling, and rate-limit awareness. | | User lifecycle management | Create users, look up a user by email, deactivate users, and suspend users (which clears their active sessions first, then suspends them). Requires the user read and/or manage scopes. | | Group management and membership | Create groups, look up a group by exact name, list all groups, and add or remove a user from a group. Requires the group read and/or manage scopes. | | Background directory sync | Continuously brings Okta users, groups (with members), and applications (with their assigned groups) into Serval on a schedule - groups refresh fully every 48 hours with a delta sync every 4 hours; users and apps sync on the standard schedule. | | Real-time sync via event hooks | Optionally, an Okta event hook notifies Serval the moment a user or group changes, and Serval refreshes just that user or group within seconds - see [Real-time sync with event hooks](#real-time-sync-with-event-hooks). | | Access management and provisioning | Grants and revokes access by adding or removing users from Okta groups (using the "Member" entitlement). Requires the group manage scope. | Anything defined in the [Okta Management API](https://developer.okta.com/docs/reference/core-okta-api/) can be accessed through Serval. ## Get your credentials Serval connects to an Okta API Services app using OAuth 2.0 client credentials. You can install Serval from the Okta Integration Network (OIN), which generates a Client ID and Client Secret for you, or create your own custom Okta API Services app using an RSA private key. In both cases you must grant the required scopes on the Okta app **and** assign the app an admin role so those scopes can actually act on resources. A custom API Services app requesting `okta.*` management scopes from Okta's Org Authorization Server must use `private_key_jwt`. Client ID and Client Secret authentication is not supported for this flow. See Okta's [OAuth service app setup guide](https://developer.okta.com/docs/guides/implement-oauth-for-okta-serviceapp/). In your Okta admin console, browse the Okta app catalog and search for **Serval** (or visit the [Serval listing on the Okta Integration Network](https://www.okta.com/integrations/serval/)). Add the integration, review the requested API scopes, and authorize it. Okta generates a Client ID and a Client Secret for your org. The Client Secret is shown only once. Copy it right away - you will not be able to view it again later. Under your admin-role assignments, give the app an admin role such as Super Administrator, a combination like Group / Organization / Application Administrator, or a least-privilege custom role with a resource set. Scopes plus the admin role together govern what Serval can do. In the Okta admin console, create a new app integration of type **API Services**, name it (for example, "Serval"), and save it. In the app's general settings, **uncheck** the "Require Demonstrating Proof of Possession (DPoP)" option. Serval does not support DPoP / proof-of-possession. If it is left enabled, token use will be rejected. Set client authentication to **Public key / Private key**, leave the key storage option set to **Save keys in Okta**, select **Add key**, and then select **Generate new key**. After Okta generates the key, select **JSON** and copy the private key. The key is not saved until you click **Done** and then **Save**. Verify that it appears in the app's Public Keys table before leaving the page. Serval accepts an RSA private key only as a single JSON Web Key (JWK) object. Do not copy the Privacy-Enhanced Mail (PEM) version, which begins with `-----BEGIN PRIVATE KEY-----`. Never paste the private key into an online converter or send it through email or chat. Grant the required scopes to the app - at minimum the read scopes for users, groups, and apps; add the manage scopes to let Serval take action. Then assign the app an admin role such as Super Administrator, Group Administrator, Organization Administrator, Application Administrator, or a least-privilege custom role with a resource set. A scope alone is not enough: scopes gate which parts of the API are available, while the admin role gates which resources Serval can actually touch. Copy the Client ID shown at the top of the app integration page and paste the complete private JWK object into Serval. The private key is shown only once and must include the `kid` matching the public key registered on the app. If your Okta interface exposes only a PEM private key, contact **[support@serval.com](mailto:support@serval.com)** without attaching the key. ## Connect in Serval Enter your credentials into the Serval connect form. For an OIN installation, use the generated Client Secret. For a custom API Services app, use the RSA private JWK. Serval automatically selects the authentication method based on what you paste into the Client Secret field. Your Okta domain without the leading "https\://" - for example, "yourcompany.okta.com". Enter the bare host with no scheme and no "-admin" suffix. Do not paste the admin console URL. If your console shows "yourcompany-admin.okta.com", strip the "-admin" and enter "yourcompany.okta.com". An invalid domain shows: "Must be a valid Okta domain (e.g., yourcompany.okta.com)". The OAuth 2.0 client ID from your Okta application - exactly 20 alphanumeric characters. An invalid value shows: "Must be a valid Okta client ID (20 alphanumeric characters)". This field is masked. For an OIN installation, paste the Client Secret generated during installation. For a custom API Services app, paste the complete RSA private JWK object generated in Okta. The value must begin with `{`; do not paste a PEM key beginning with `-----BEGIN PRIVATE KEY-----`. When editing an existing connection, you can leave this field blank to keep the stored secret unchanged. The stored secret is always shown masked, never in clear text. A comma-separated list of OAuth scopes. Serval pre-fills a default set covering app, user, and group read and manage plus log read. These scopes must also be granted on the Okta app itself. Not all of the pre-filled scopes are required - you can remove any scopes you don't need. An empty list is rejected. Each scope must follow the expected format, otherwise you will see: "Each scope must follow the format okta.\.\ or okta.\.\.\ (e.g., okta.users.read, okta.accessRequests.catalog.read). SSF scopes are ssf.\ (e.g., ssf.read, ssf.manage)." ## Verifying the connection After you connect, Serval runs a series of health checks against your Okta org and reports the result of each one. Each health check is an API call that exercises a specific scope, so the checks always run regardless of which scopes you configured - a check whose scope you removed will simply fail with a missing-scope message. This is expected if you intentionally trimmed the scope list, and you can safely ignore failures for capabilities you don't plan to use. * **List Okta Apps** confirms Serval can list applications. On success it reports "Successfully listed" followed by the number of apps found. On failure it reports "Unable to list apps." If the required scope is missing in Serval, it reports "Missing required scope in Serval: okta.apps.read". * **List Okta Users** confirms Serval can list users. On success it reports "Successfully listed" followed by the number of users found. On failure it reports "Unable to list users." If the scope is missing, it reports "Missing required scope in Serval: okta.users.read". * **List Okta Groups** confirms Serval can read groups. On success it reports "Successfully listed" followed by the number of groups found. On failure it reports "Unable to list groups." If the scope is missing, it reports "Missing required scope in Serval: okta.groups.read". * **Manage Okta Groups** creates a temporary test group (named with a "serval-healthcheck-" prefix) and immediately deletes it to verify write access. On success it reports "Successfully created and deleted test group:" followed by the test group's name. On failure it reports "Unable to create and delete groups." If the scope is missing, it reports "Missing required scope in Serval: okta.groups.manage". When a check fails with a permission error, Serval adds: "The correct scope is configured in Serval, but the OAuth application may need admin consent or additional admin roles in Okta." When Okta returns a server error, Serval adds: "Okta returned a server error. This is likely a temporary issue with Okta's API - please try again later." The most common surprise: the scope is configured correctly in Serval but a check still fails with a permission error. This almost always means the Okta app is missing the admin role (or admin consent). Assign the app an admin role under your admin-role assignments - a scope on its own is not enough. ## Real-time sync with event hooks By default, Serval learns about changes in Okta on the background sync schedule, so a change can take hours to appear. With an Okta event hook configured, Okta notifies Serval the moment a user or group changes, and Serval re-fetches just that user or group - changes typically appear in Serval within seconds. This is optional and additive: the background directory sync keeps running either way, acting as a safety net for anything the event hook misses. No additional OAuth scopes are required - event hooks reuse the same scopes your directory and resource sync already use. If you don't see the **Webhooks** section described below on your Okta application's Settings tab, make sure user or resource (group) sync is enabled for this Okta app - the section only appears once one of those syncs is turned on. If it's still missing, contact **[support@serval.com](mailto:support@serval.com)**. In Serval, go to **Integrations**, open your Okta application, and switch to the **Settings** tab. The **Webhooks** section shows two values: a **Webhook URL** (on Serval's public API host) and a **Secret**. Copy both. The Secret can be re-copied from this page at any time - unlike Okta, Serval does not hide it after setup. In the Okta admin console, go to **Workflow → Event Hooks** and choose **Create Event Hook**. Give it a name (for example, "Serval real-time sync") and fill in: * **URL**: the Webhook URL copied from Serval. * **Authentication field**: `X-Webhook-Secret` * **Authentication secret**: the Secret copied from Serval. * **Custom header fields**: leave empty. Paste the Secret exactly as copied - no quotes and no trailing whitespace. Serval compares the value character-for-character and rejects anything that doesn't match. The **Subscribe to events** box starts empty - add the events Serval acts on. Okta lists them by friendly name; these are the ones that trigger a refresh (API event type in parentheses). User events (for user sync): * User created (`user.lifecycle.create`) * User activated (`user.lifecycle.activate`) * User deactivated (`user.lifecycle.deactivate`) * User suspended (`user.lifecycle.suspend`) * User unsuspended (`user.lifecycle.unsuspend`) * User's Okta profile updated (`user.account.update_profile`) Group events (for resource sync): * Group created (`group.lifecycle.create`) * Group profile updated (`group.profile.update`) * User added to group (`group.user_membership.add`) * User removed from group (`group.user_membership.remove`) Directory group events (for LDAP/AD-sourced groups, whose changes Okta logs under different event types): * Group imported from a directory (`system.import.group.create`) * Group deleted from a directory (`system.import.group.delete`) * Group imported or updated from an app (`app.user_management.user_group_import.upsert_success`) * Directory group member imported or removed (`app.user_management`) The listed group events refresh the affected group and its members when they include a canonical Okta group ID. The existing `system.import.group.create` and `system.import.group.delete` handlers require a `UserGroup` target and don't trigger a delta when it's missing. For a directory delete event, Serval removes the group only when Okta confirms it no longer exists. Native group deletion (`group.lifecycle.delete`) remains on scheduled sync. Only successful `app.user_management` and `app.user_management.user_group_import.upsert_success` events can trigger the delta fallback. These are exact event types. They refresh the group directly when they identify one canonical group. If the group ID is missing or ambiguous, Serval batches the events for 30 seconds, then syncs groups changed since the last successful group sync. It queries Okta's group profile and membership update timestamps, then refreshes the returned groups and their members. It checks deletion events separately. A successful sweep ends without an automatic repeat; events received during the sweep queue another pass. The directory group update event (`system.import.group.update`) isn't [eligible for event hooks](https://developer.okta.com/docs/reference/api/event-types/#system-import-group-update). Timestamp-based group sync discovers imported group renames, including during scheduled sync. The checkpoint advances only after the group and membership sync completes successfully. Overlapping time windows reduce missed changes from delayed events. Scheduled syncs continue to reconcile the directory; webhooks don't guarantee immediate visibility of every LDAP or Active Directory change. Other event types are ignored, except extra `user.*` or `group.*` events, which re-fetch the affected user or group when an ID is available. For an existing hook, add the directory event subscriptions in Okta; updating Serval doesn't change your hook's subscriptions. Save the hook and click **Verify**. Okta sends a one-time verification challenge to the Webhook URL, which Serval answers automatically. The hook shows as "Verified" in Okta. From this point on, changes flow to Serval as they happen. ## Gotchas and troubleshooting A custom API Services app requesting `okta.*` management scopes cannot authenticate to the Org Authorization Server with a Client ID and Client Secret. In the app's Client Credentials settings, select **Public key / Private key**, generate and save an RSA key, and paste the complete private JWK object into Serval's Client Secret field. When editing an existing Serval connection, do not leave the field blank: a blank value preserves the previously stored client secret. Scopes typed into the Serval form are only the scopes requested on the token. They must **also** be granted on the Okta API Services app, and the app must be assigned an admin role (or a custom role plus resource set). Scopes gate which part of the API is available; the admin role gates which resources can be acted on. Add the missing scope on the Okta app and assign it an admin role under your admin-role assignments. Serval only connects to "okta.com" and "oktapreview\.com" hosts. The connect form's validation will accept an "okta-emea.com" domain, but requests to EMEA-cell domains will fail once they actually run. Use an "okta.com" or "oktapreview\.com" domain. The API Domain field expects a bare host such as "yourcompany.okta.com". Do not include "https\://", and do not copy the admin console URL - "yourcompany-admin.okta.com" is wrong; strip the "-admin" to get "yourcompany.okta.com". The domain is used as both the token host and the API base, so a wrong value breaks everything downstream. Serval decides between the plain-secret and private-key methods by whether the Client Secret value is a key in JSON form. Paste the **complete RSA private JWK object** into the Client Secret field. It must begin with `{` and include the private-key parameters and the `kid` matching the public key registered on the same Okta app. A PEM value beginning with `-----BEGIN PRIVATE KEY-----` is treated as a plain client secret and can produce an `HTTP 401 (invalid_client)` response. A non-RSA JWK fails token generation with "key is not an RSA private key". If the Okta interface exposes only PEM, contact **[support@serval.com](mailto:support@serval.com)** without attaching the key. Serval does not support DPoP / proof-of-possession. In the custom API Services app's general settings, uncheck the "Require Demonstrating Proof of Possession (DPoP)" option before connecting, otherwise token use will be rejected. On update, Serval still requires Scopes, Client ID, and API Domain, but the Client Secret is optional. Leave it blank to keep the existing stored secret unchanged, or paste a new value to replace it. The stored secret is always returned masked. Okta enforces roughly 250 requests per minute per application on the groups and apps endpoints. Serval paces background syncs to stay under this limit and automatically retries when throttled, but heavy custom workflows against these endpoints can still hit Okta's rate limits. Check the URL first: it must be the exact Webhook URL copied from the Webhooks section of your Okta application's Settings tab in Serval, with no edits. A 404 during verification almost always means the URL is wrong or truncated. If the URL is correct and verification still fails, re-copy the Secret from Serval and re-save the hook - remember it must be pasted exactly into the `X-Webhook-Secret` authentication field. Confirm the hook is subscribed to the event types listed in [Real-time sync with event hooks](#real-time-sync-with-event-hooks) - a verified hook with no matching subscriptions delivers nothing useful. Also check Okta's event hook preview/delivery log to confirm Okta is sending events and receiving successful responses. If deliveries succeed but nothing changes in Serval, the secret may be wrong: Serval acknowledges every delivery (so Okta shows success) but rejects events whose `X-Webhook-Secret` value doesn't match. Re-copy the Secret from Serval and update the hook. The scheduled background sync still keeps data correct in the meantime. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Okta integration. # Omnissa Workspace ONE UEM Source: https://docs.serval.com/sections/integrations/omnissa-workspace-one-uem Connect Omnissa Workspace ONE UEM (formerly VMware Workspace ONE / AirWatch) to Serval to search enrolled devices, look up enrollment users, send device commands, and manage tags and smart groups from Serval workflows. ## About Omnissa Workspace ONE UEM Omnissa Workspace ONE UEM is a unified endpoint management (UEM) platform for iOS, Android, macOS, Windows, Linux, and rugged devices. Connecting it to Serval lets your team search device inventory, look up which devices belong to a user, send device commands such as lock or enterprise wipe, and manage tags, smart groups, and organization groups—all through Serval workflows that call the Workspace ONE UEM REST API on your behalf. Serval only ever sends authenticated requests to the exact API host you configure. **Authentication:** OAuth 2.0 client credentials. You create an OAuth client in the UEM console and give Serval the client ID, client secret, your tenant's REST API host, and the Omnissa token-service region. Serval stores the client ID and an encrypted copy of the secret, exchanges them for short-lived bearer tokens against Omnissa's token service, and refreshes tokens automatically. No API key (`aw-tenant-code`) is needed. **Data sync:** On demand. Workflows call the UEM APIs when they run, subject to each workflow's approval procedure. There's no background sync or webhook. ## What the integration enables | Capability | Description | | - | - | | Device inventory | Search enrolled devices by user, platform, model, ownership, compliance status, or last-seen date; look up a single device by serial number, UDID, MAC address, or IMEI; and read installed apps. | | Device commands | Send UEM commands to a device. The prebuilt workflow offers the non-destructive set (lock, query, sync, clear passcode, soft reset, shutdown); enterprise wipe and device wipe remain available to custom workflows through the API action, where you set the approval procedure yourself. | | Users and groups | Search enrollment users, read organization groups, read smart groups and their members, and add or remove device tags. | | Applications | Search internal, public, and purchased apps and check their install status on devices. | | Full API access in custom workflows | Custom Serval workflows can call any endpoint in the MDM, System, MAM, MCM, and MEM API groups across API versions 1 through 4, with typed request and response schemas. | | Connection health checks | Four built-in checks exercise tenant info, device search, user search, and smart groups, so a missing admin-role permission shows up as exactly one failing check. | Anything documented on your tenant's API help page (`https:///api/help`) or in the [Workspace ONE UEM API reference](https://developer.omnissa.com/workspace-one-uem-apis/) can be accessed through Serval. ## Get your credentials You need four things from Workspace ONE UEM: the **REST API host**, the **token region**, and an OAuth **client ID** and **client secret**. Omnissa's guide is [Using UEM Functionality With a REST API](https://docs.omnissa.com/bundle/WorkspaceONE-UEM-Console-BasicsVSaaS/page/UsingUEMFunctionalityWithRESTAPI.html). In the UEM console, switch to your Customer organization group (or below) and go to **Groups & Settings** > **All Settings** > **System** > **Advanced** > **API** > **REST API**. The **REST API URL** looks like `https://as1234.awmdm.com/API`. The host is the part before `/API`, for example `as1234.awmdm.com`. On-premises tenants use their own hostname. Ignore the **API Key** on this page. Serval authenticates with an OAuth client, which doesn't need the `aw-tenant-code` key. Omnissa mints OAuth tokens from a regional token service, separate from your API host. Look up your data center in Omnissa's **Datacenter and Token URLs** table (linked from the guide above) and note the region: **North America**, **EMEA**, **Asia Pacific**, or **UAT** for pre-production tenants. The token URLs are `https://na.uemauth.workspaceone.com/connect/token`, `https://emea.uemauth.workspaceone.com/connect/token`, `https://apac.uemauth.workspaceone.com/connect/token`, and `https://uat.uemauth.workspaceone.com/connect/token`. Older documentation lists the same regions on `uemauth.vmwservices.com`. Omnissa is retiring those hosts; Serval uses the `workspaceone.com` hosts. Go to **Accounts** > **Administrators** > **Roles** and create a role that grants only the REST API permissions Serval needs—at minimum the read permissions for devices, users, and smart groups covered by the health checks, plus any device-command or tag permissions your workflows use. You can widen the role later without reconnecting. Go to **Groups & Settings** > **Configurations** > **OAuth Client Management** and click **Add**. Name the client (for example, "Serval"), pick the organization group it should operate in, assign the role from the previous step, set the status to **Enabled**, and save. Copy both values immediately and store them securely. Workspace ONE UEM shows the client secret only once. If you lose it, create a new OAuth client. ## Connect in Serval In Serval, open **Integrations**, find **Omnissa Workspace ONE UEM** on the **All integrations** tab, and start a new connection. Enter your tenant's REST API host, for example `as1234.awmdm.com`, without `https://`, a path, or a port. The form rejects anything else with: "Enter a hostname such as as1234.awmdm.com (no https\://, path, or port)". Choose **North America**, **EMEA**, **Asia Pacific**, or **UAT / pre-production** to match your data center. Paste the OAuth client's ID and secret. Save, then verify the connection using the health checks below. **When editing an existing connection:** the stored client secret is shown obfuscated, so paste the full secret again to change it. Leaving **API Host** or **Token Region** unchanged keeps the saved values. Serval pins the bearer token to the exact API host you configured. A workflow request to any other host—including another tenant's `awmdm.com` host—receives no credentials. ## Verifying the connection The integration ships four health checks: 1. **Test Workspace ONE UEM Connection**: obtains a token and reads tenant info. Success: "Successfully authenticated with Workspace ONE UEM at \[your API host] (version \[UEM version])". 2. **List Workspace ONE UEM Devices**: searches devices with a page size of one and reports the enrolled total. 3. **List Workspace ONE UEM Enrollment Users**: searches enrollment users with a page size of one. 4. **List Workspace ONE UEM Smart Groups**: lists smart groups with a page size of one. Each failure starts with "Unable to ..." followed by a specific reason. A `401` adds "Workspace ONE UEM rejected the OAuth client credentials. Verify the Client ID, Client Secret, and token region in the integration settings." A `403` adds "The OAuth client's admin role does not grant this permission." If the connection check passes but one of the other checks fails, authentication works and the OAuth client's admin role is missing that one resource permission. Fix it in **Accounts** > **Administrators** > **Roles**. ## Gotchas and troubleshooting The most common cause is a token region that doesn't match your data center: the token service returns `401` for clients it doesn't know about. Confirm the region against Omnissa's Datacenter and Token URLs table and edit the connection. Also confirm the OAuth client's status is **Enabled** in the UEM console. Workspace ONE UEM authorizes each REST endpoint through the admin role assigned to the OAuth client. A `403` means the role lacks that resource's permission, not that the credentials are wrong. Add the permission to the role; no reconnect is needed. The OAuth client operates in the organization group you chose when creating it and sees devices in that group and its children. Create the client at your Customer organization group to see the whole tenant, or pass `lgid` in device searches to target a specific group. UEM search endpoints are paged with `page` (starting at 0) and `pagesize` (maximum 500) and return a `Total`. Custom workflows should keep requesting pages until `page * pagesize` reaches `Total`. Workspace ONE UEM selects the API version from the `Accept` header, and the same path can exist in several versions. Serval exposes one action per version: `apiRequest` sends version 1, and `apiRequestV2`, `apiRequestV3`, and `apiRequestV4` send the newer versions. Use the action matching the version tab on the API help page. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Omnissa Workspace ONE UEM integration. # OneLogin Source: https://docs.serval.com/sections/integrations/onelogin Connect Serval to OneLogin to sync users, applications, and roles, and to provision access by managing OneLogin role membership. ## About OneLogin OneLogin is an identity and access management (IdP) platform. Serval connects to your OneLogin account using an API credentials pair scoped to your OneLogin subdomain and works against the OneLogin API v2. Once connected, Serval keeps your user directory, application catalog, and roles (including who belongs to each role) in sync, and can grant or revoke access by adding or removing users from OneLogin roles. **Authentication:** OAuth 2.0 client credentials - you paste a Subdomain, Client ID, and Client Secret from a OneLogin API credentials pair. There is no browser sign-in step. **Data sync:** Background syncs pull users every 4 hours, and applications and roles every 48 hours (role and membership changes are also picked up by a faster 4-hour delta sync between full role syncs). Access changes run on demand from workflows. ## What the OneLogin integration enables | Capability | Description | | - | - | | User sync | Imports your full OneLogin user directory every 4 hours, including email, first and last name, manager, and active status. Users whose OneLogin status is anything other than Active are marked deactivated in Serval. | | App sync | Imports your OneLogin application catalog every 48 hours, including app names and icons, and links each app to the OneLogin roles that grant access to it. | | Role (group) sync | Imports OneLogin roles as Serval groups - a full sync every 48 hours plus a 4-hour delta sync - along with each role's members. Roles serve as the group source for this integration, and membership is the single entitlement on each role ("Member of this OneLogin role"). | | Access management | Adds or removes a user from a OneLogin role on demand from workflows. The target user is matched by their email address. | | Custom workflow API access | Workflows can call the integration's typed OneLogin API v2 operations - users (including a user's apps and roles), roles (including a role's members, admins, and apps), and applications (including an app's users) - with automatic retry and rate-limit handling built in. | The workflow surface is generated from the [OneLogin API v2](https://developers.onelogin.com/api-docs/2/getting-started/dev-overview) definitions for the user, role, and application endpoints listed above. ## Get your credentials Serval authenticates with an API credentials pair (Client ID and Client Secret) created in your OneLogin admin console. See OneLogin's guide to [working with API credentials](https://developers.onelogin.com/api-docs/2/getting-started/working-with-api-credentials) for full details. You need admin access to create API credentials. This is where OneLogin manages API credential pairs. Give it a name (e.g. Serval) and pick a scope: **Read all** for sync-only, **Manage all** if Serval will add and remove users from roles. OneLogin generates the credential pair. Keep them somewhere safe until you finish connecting in Serval. The Client Secret is only shown once, at creation time. If you lose it, you will need to create a new credential. The scope you pick here determines everything Serval can do. **Read all** is enough for syncing users, apps, and roles. Choose **Manage all** if you want Serval to provision access by changing role membership. ## Connect in Serval Find **OneLogin** in the Serval integrations list and open the connect form. "Your OneLogin domain, e.g. `acme.onelogin.com`. Do not include https\://." Leaving it blank shows "This field is required". "API credentials Client ID. Generate one in OneLogin under Developers > API Credentials." Leaving it blank shows "This field is required". "API credentials Client Secret". Entered as a password field. This field has no inline blank-field message - submitting without it fails with a generic "Failed to install integration" error, so paste the secret before you submit. Click **Submit**. Serval exchanges the Client ID and Client Secret for an access token against your subdomain and uses it for all OneLogin requests. When you later edit the connection, Subdomain and Client ID come back pre-filled with their saved values, and the saved Client Secret displays obfuscated (bullets plus its last 4 characters) with a control to replace it. Any field you leave blank - and a secret left as its obfuscated placeholder - keeps its existing saved value, so you can rotate just the secret without re-entering the Subdomain or Client ID. ## Verifying the connection The integration ships four health checks you can run from the integration's page in Serval. **Test OneLogin Connection** - verifies the integration is configured correctly and can authenticate against the OneLogin API with a minimal read-only call. * Success: "Successfully authenticated with OneLogin" * Failure: "Unable to connect to OneLogin." followed by a hint - "The OneLogin client credentials are invalid or expired. Verify the client ID and client secret in the integration settings." (bad credentials), "The OneLogin API credential lacks the required scope. Use 'Read all' for sync-only, or 'Manage all' if access management is needed." (insufficient scope), or "OneLogin returned a server error. This is likely a temporary issue with OneLogin's API - please try again later." (OneLogin-side errors). Other errors show the base message alone. **List OneLogin Users** - checks that Serval can list users from your directory. Success: "Successfully listed \[number] users from OneLogin" **List OneLogin Roles** - checks that Serval can list roles. OneLogin "Roles" are the equivalent of "User Groups" in other IdPs. Success: "Successfully listed \[number] roles from OneLogin" **List OneLogin Applications** - checks that Serval can list applications. Success: "Successfully listed \[number] applications from OneLogin" The three list checks fail with "Unable to list users from OneLogin." / "Unable to list roles from OneLogin." / "Unable to list applications from OneLogin." followed by a hint - "OneLogin rejected the request as unauthenticated. Check the client ID and secret." (bad credentials), "OneLogin denied the request. The API credential may not have the required scope." (insufficient scope), or "The OneLogin resource was not found. This may indicate an incorrect subdomain or missing permissions." (often a wrong Subdomain). All four health checks only need read access, so every check can pass with a **Read all** credential while adding or removing users from roles still fails with permission errors. If syncs look healthy but access changes fail, recreate the credential with **Manage all** scope. ## Gotchas and troubleshooting In OneLogin, "Roles" are what most identity providers call user groups - users gain application access via role membership, and Serval models OneLogin roles as group resources with a single Member entitlement. OneLogin "Groups" are security policies and are intentionally not modeled in Serval. Do not expect OneLogin Groups to appear as Serval resources. Serval requests no scopes of its own during authentication - effective permissions come entirely from the scope assigned to the API credential in OneLogin. Use **Read all** for sync-only, or **Manage all** if access management is needed. A credential with too narrow a scope produces permission-denied errors on health checks and syncs. The Subdomain field expects the full OneLogin domain (e.g. `acme.onelogin.com`) without https\://. Serval only attaches credentials to requests going to a domain of the form `yoursubdomain.onelogin.com`, so a custom branded domain outside onelogin.com will not work. Authentication is also performed against this value, so a wrong Subdomain breaks the connection entirely - "not found" hints on health checks often indicate an incorrect Subdomain. When a workflow adds or removes a user from a role, Serval finds the user's OneLogin account by exact email match. If no account matches, the workflow fails with "No OneLogin user found with email: \[email]"; if more than one matches, it fails with "Multiple OneLogin users found with email: \[email]". Each person must have exactly one OneLogin account whose email matches their Serval email. On the update form, every field comes back pre-filled and the Update button stays disabled until you change something. Any field you clear and submit blank (or a Client Secret left as its obfuscated bullet placeholder) keeps the existing stored value - the saved secret displays as bullets plus its last 4 characters, with a control to replace it. This means you can rotate just the secret without touching the Subdomain and Client ID, but it also means clearing a field does not delete the saved value. Serval automatically retries OneLogin requests that fail with timeouts, rate limits, or temporary server errors. When OneLogin rate-limits a request, Serval waits until the time OneLogin specifies before retrying; otherwise it backs off with increasing delays. Persistent server errors generally indicate a OneLogin-side issue - wait and try again later. OneLogin returns the next-page token in a response header, which must be passed back as a cursor on the next request - and OneLogin rejects requests that combine a cursor with other pagination settings, so a page-size limit should only be sent on the first request. In custom workflows, use the "OneLogin API request with headers" action, which exposes response headers, to paginate; the plain "OneLogin API request" action discards headers and cannot fetch subsequent pages. See OneLogin's notes on [pagination](https://developers.onelogin.com/api-docs/2/getting-started/using-query-parameters#pagination). *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your OneLogin integration. # Oomnitza Source: https://docs.serval.com/sections/integrations/oomnitza Connect Serval to your Oomnitza instance with a dedicated service account to automate IT asset management workflows across assets, software, SaaS, people, locations, and contracts. ## About Oomnitza [Oomnitza](https://www.oomnitza.com) is an IT asset management (ITAM) platform that tracks your hardware, software, SaaS applications, and the people and places they belong to. The Serval integration connects to your company's own Oomnitza instance (for example, company.oomnitza.com) using a dedicated service account, and gives your workflows fully typed access to the Oomnitza REST API: assets, accessories, kits, software, SaaS applications and users, people, locations, stockrooms, contracts, subscriptions, custom objects, request portal requests, activity feeds, saved searches, and bulk operations. **Authentication:** Choose one of two methods when you connect. An Oomnitza API token (recommended for Oomnitza API v3) or Basic authentication with a service account username and password. You enter your choice along with your Oomnitza domain. **Data sync:** On-demand only. Serval calls Oomnitza when a workflow runs and when you run the connection's health checks - there is no background sync, entity ingestion, or webhook subscription. ## What the Oomnitza integration enables | Capability | Description | | - | - | | Asset management | List, search, create, create-or-update, edit, and delete hardware assets; read each asset's installed software, change history, and saved searches. | | Accessories and kits | Full create, read, update, and delete for accessories and kits, plus search, change history, and saved searches. | | Software and license tracking | Create, list, search, edit, and delete software titles; see which assets have each title installed, and read change history and saved searches. | | SaaS and SaaS user management | Manage SaaS records, SaaS roles and role members, and the users assigned to each SaaS, including activating or deactivating SaaS users. | | People and user records | Create, list, search, edit, and delete Oomnitza user records; read a user's assets, SaaS and software assignments, profile settings, change history, and saved searches. | | Locations and stockrooms | Full create, read, update, and delete for locations and stockrooms, plus search, change history, and saved searches. | | Contracts and subscriptions | Create, search, edit, and delete contracts; read each contract's licenses, change history, and saved searches; and full create, read, update, and delete for subscriptions. | | Custom objects | Define custom objects and create, search, create-or-update, edit, and delete their records, including change history. | | Activity feed and bulk operations | Read the user activity feed with filters, run bulk edit and bulk delete jobs with status polling, activate Oomnitza workflows, and read connector run logs. | Anything defined in the [Oomnitza API](https://oomnitza.zendesk.com/hc/en-us/articles/17200339347991-Oomnitza-REST-APIs) can be accessed through Serval. ## Get your credentials Serval authenticates with either an Oomnitza API token or a service account username and password. Either way, create a dedicated account rather than using a personal login - a dedicated account survives staff changes, makes the credential easier to audit and rotate, and its role can be scoped to exactly what your workflows need. See the [Oomnitza REST API documentation](https://oomnitza.zendesk.com/hc/en-us/articles/17200339347991-Oomnitza-REST-APIs) for background on API access. Oomnitza's help center requires signing in with your Oomnitza account, so the documentation links on this page may prompt you to log in first. Sign in at your organization's URL, for example [https://company.oomnitza.com](https://company.oomnitza.com). Go to **Configuration > User Management** and create a new user with a role that has API access. Use a descriptive name such as **Serval Integration Service**. Go to **Configuration > Security > API tokens** and generate a token for the service account. The token is displayed only once, so copy it before you leave the page - it cannot be recovered afterward. You will enter it in the Serval connect form along with your domain. Sign in at your organization's URL, for example [https://company.oomnitza.com](https://company.oomnitza.com). Go to **Configuration > User Management** and create a new user with a role that has API access. Use a descriptive name such as **Serval Integration Service**. Note the username and password - you will enter them in the Serval connect form along with your domain. Whichever method you use, the service account's role needs at least **read permission on Users, Assets, and Locations**. Serval's connection health checks probe all three modules, so a role missing any of them will show a failing connection even when your workflows only touch other objects. Menu names can vary between Oomnitza versions. If you do not see **Configuration > User Management** or **Configuration > Security > API tokens**, check Oomnitza's documentation for where user roles, accounts, and API tokens are managed in your instance. ## Connect in Serval In Serval, open the Oomnitza integration and start a new connection. Type the bare hostname of your instance, for example company.oomnitza.com - the placeholder and helper text ("Your Oomnitza domain (e.g., company.oomnitza.com)") show the expected shape. An https\:// prefix, a trailing slash, a path, bare oomnitza.com, or a nested subdomain is rejected with "Please enter a valid Oomnitza domain (e.g., company.oomnitza.com)". Leaving it blank flags "This field is required". This domain also becomes the connection's display name in Serval. Pick **API token** or **Basic authentication**. The form defaults to **API token** and shows only the credential fields for the method you select. For **API token**, enter the token you generated in Oomnitza (helper text: "Your Oomnitza API token from Configuration > Security > API tokens"). For **Basic authentication**, enter your service account **Username** and **Password**. After saving, Serval only ever displays the token or password obfuscated - bullet characters followed by its last 4 characters. Save, then verify the connection using the health checks below. **When editing an existing connection:** the domain appears in plain text, and the stored secret (the API token, or the username and password for Basic auth) appears obfuscated with a **Replace** button. Leave the secret untouched and the stored credentials are kept as-is. For Basic auth, the username and password are stored as a pair, so to change either one, click **Replace** and enter both. Leaving the domain blank keeps the previously saved domain. After you save changes, Serval automatically re-runs the connection's health checks. ## Verifying the connection The integration ships three health checks, each fetching a single record from your instance. Run them from the connection's page in Serval; they also run automatically after you save changes to the connection. | Health check | What it verifies | Success message | | - | - | - | | List Oomnitza Users | The stored credentials authenticate against your instance | "Successfully connected to Oomnitza and retrieved users" | | List Oomnitza Assets | The service account can read asset records | "Successfully retrieved assets from Oomnitza" | | List Oomnitza Locations | The service account can read location records | "Successfully retrieved locations from Oomnitza" | On failure you will see, respectively: "Unable to list Oomnitza users. Please verify your API key is valid.", "Unable to list Oomnitza assets. Please verify your API key has the required permissions.", and "Unable to list Oomnitza locations. Please verify your API key has the required permissions." If "List Oomnitza Users" passes but the assets or locations checks fail, your credentials are fine - the service account's role is missing read permission on the Assets or Locations module. Grant the role read access in Oomnitza, then run the checks again. ## Gotchas and troubleshooting The Oomnitza Domain field accepts exactly one subdomain of oomnitza.com - enter company.oomnitza.com and nothing else. An https\:// prefix, a trailing slash, any path, bare oomnitza.com, a nested subdomain (like a.b.oomnitza.com), or a non-oomnitza.com host all fail with "Please enter a valid Oomnitza domain (e.g., company.oomnitza.com)". API token is recommended for Oomnitza API v3 and is the form's default - generate one under **Configuration > Security > API tokens**. Use Basic authentication (service account username and password) only if your Oomnitza tenant requires it. Serval shows only the credential fields for the method you select, so set the **Authentication Method** selector before entering credentials. Serval stores your token (or your username and password) as a single API-key-style credential, so failure messages reference "your API key". Read them as: the token or username/password is wrong, or the account's role lacks read permission on the module that check probes (Users, Assets, or Locations). For Basic authentication, the username and password are stored and updated as a pair, and the pair is only replaced when both fields are submitted with real values. If you edit the username but leave the password untouched (still showing its obfuscated value), the previous username and password stay in place. To change either one, click **Replace** on the password field and enter the password along with the username. Serval injects credentials only for requests to version 3 of the Oomnitza REST API on your oomnitza.com domain. Calls to other Oomnitza paths or older API versions receive no credentials and will fail to authenticate. Three things to know when using the Oomnitza API action in workflows. First, use curly-brace placeholders (such as `{ident}`) with path parameters - colon-style placeholders are not substituted. Second, list endpoints paginate with `skip` and `limit` query parameters and return a plain JSON array: keep paging until a page returns fewer items than the limit. Third, updating non-system edit-only fields on create and edit calls requires the optional `Oomnitza-Ignore-Meta-Restriction` header (values 0 or 1) set to 1. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Oomnitza integration. # Opal Security Source: https://docs.serval.com/sections/integrations/opal Connect Opal Security to Serval so workflows can look up, provision, and revoke access, and file and approve access requests in Opal. ## About Opal Security Opal Security is an access management platform for governing user access to groups, resources, and applications. Serval connects to Opal with an API token created by an Opal administrator, and workflows can then look up a user's current access, add or remove group membership, and submit, review, and approve access requests. Production (api.opal.dev) and sandbox (sandbox.opal.dev) connect as separate instances, each identified by its API domain. **Authentication:** API token (bearer) - you provide your Opal API Domain and an API Token. **Data sync:** On demand only. There is no background sync; Serval calls the Opal API live each time a workflow runs. ## What the Opal Security integration enables | Capability | Description | | - | - | | Access management | Look up, provision, and revoke user access. Includes workflows to get a user's Opal ID by email, view their current group access, resource access, or complete access, check access to a specific resource, and add or remove a user from an Opal group. | | Access requests | Submit, review, and approve access requests. Includes workflows to request group access for a user, list pending requests, approve a request, and get request details by ID. Group requests go through Opal's normal approval workflow and return a trackable request link. | | Discovery | Standalone workflows to list Opal owners (including their users and escalation settings) and to list the groups users can request access to. | | Full Opal API access | Workflows can reach anything in the Opal REST API through Serval's authenticated connection, covering apps, bundles, groups, group bindings, resources, users, owners, access requests, events, sessions, IdP group mappings, and non-human identities. | Anything defined in the [Opal API](https://docs.opal.dev/reference) can be accessed through Serval. ## Get your credentials You need an API token created by an Opal administrator. The token needs read access to users, groups, and resources for the connection checks to pass, and write or provisioning permission if you plan to use the add/remove-user or access-request workflows. See the [Opal API reference](https://docs.opal.dev/reference) for details on Opal's API tokens. Sign in to Opal and open your organization's Settings page, then select the API Tokens section. Click Create Token, give it a descriptive name (for example, "Serval Integration"), and select the permissions appropriate for your use case. Copy the generated API Token right away - Opal displays it only once. If you lose it, you will need to create a new token. Use api.opal.dev for production or sandbox.opal.dev for sandbox. Opal shows the token value a single time, at creation. Store it securely before leaving the page. Read access to users, groups, and resources is required for the post-connect health checks to pass. Provisioning workflows (adding or removing users, approving access requests) additionally need write permission. ## Connect in Serval In Serval, find Opal Security in the app catalog and start a new connection. The connect form has two fields. Type the bare domain only, exactly as shown in the placeholder "api.opal.dev". The helper text reads "Your Opal API domain (e.g., api.opal.dev or sandbox.opal.dev)". Do not include a protocol, path, or port. Leaving it blank shows "This field is required". If the domain is not a valid Opal domain, the save fails with "Failed to install integration: Invalid API domain: invalid API domain format: must be a valid Opal domain (e.g., api.opal.dev or sandbox.opal.dev)". Paste the full token into the API Token password field (helper text: "Your Opal API bearer token"). The form does not check the token at all - a blank, mistyped, or revoked token still saves, and the problem only surfaces when the health checks run after you connect. Submit the form, then confirm all four health checks pass (see below). After saving, the token is displayed only as an obfuscated value with its last 4 characters visible. Want both production and sandbox? Connect each domain separately - each one is its own connection, identified by its API domain. When editing an existing connection, the saved token shows only as an obfuscated value. Use the Replace button (reconnect dialog) or the pencil icon (integration settings page) and paste the complete new token - never a partial value, and never submit a cleared token field. Whenever you change anything about the connection, replace the token in full as part of the same save, then confirm the health checks pass. ## Verifying the connection The connection ships four health checks that make live calls to Opal: * **Test Opal Connection** - verifies Serval can authenticate with Opal using your token. Success: "Successfully authenticated with Opal Security". Failure: "Unable to connect to Opal Security. Please verify your API token is valid and has the necessary permissions." * **List Opal Users** - verifies the token can read user data by listing a small sample of users. Success: "Successfully listed users from Opal Security (sample size: \[number])". Failure: "Unable to list users from Opal Security. Please verify the API token has permission to read user data." * **List Opal Groups** - verifies the token can read group data by listing a small sample of groups. Success: "Successfully listed groups from Opal Security (sample size: \[number])". Failure: "Unable to list groups from Opal Security. Please verify the API token has permission to read group data." * **List Opal Resources** - verifies the token can read resource data by listing resources. Success: "Successfully listed resources from Opal Security (sample size: \[number])". Failure: "Unable to list resources from Opal Security. Please verify the API token has permission to read resource data." All four checks test read access only. A connection can show all green and still fail provisioning workflows (adding or removing users, approving access requests) if the token lacks write permission. If lookups work but provisioning fails, create a token with write permission in Opal and replace the token on the connection. ## Gotchas and troubleshooting On the integration settings page, the saved token shows as an obfuscated value (bullets plus the last 4 characters) with a small pencil (edit) icon next to it. Click the pencil, paste the complete new token into the input (placeholder: "Enter new value"), and click Update. In the reconnect dialog, the same field shows a Replace button instead - click it and paste the full new token there. Either way, always paste the entire token: never submit a cleared or partial token field, and whenever you edit anything else about the connection (for example the API Domain), replace the token in full as part of the same save. Then confirm all four health checks pass. The API Domain must be exactly one label followed by .opal.dev - for example api.opal.dev or sandbox.opal.dev. Values with a protocol ([https://api.opal.dev](https://api.opal.dev)), a path (api.opal.dev/v1), a multi-level subdomain (foo.bar.opal.dev), or a self-hosted custom domain are rejected. On first connect this surfaces as "Failed to install integration: Invalid API domain: invalid API domain format: must be a valid Opal domain (e.g., api.opal.dev or sandbox.opal.dev)". When editing an existing connection from the integration settings page, the same problem shows as "Failed to update configuration". Serval appends the API version path automatically. Enter the bare domain only - adding "/v1" (or any path) to the API Domain fails validation. The token is never validated when you connect - even a blank token saves without an error. A missing or under-permissioned token surfaces afterward: a token that cannot authenticate fails Test Opal Connection, and a token missing read access to users, groups, or resources fails the matching check with a "Please verify the API token has permission to read ... data" message. Fix the token's permissions in Opal, then replace the token on the connection (pencil icon or Replace button) and re-run the checks. The token value is displayed a single time when it is created in Opal. If it is lost, create a new token in Opal and replace the token on the Serval connection, pasting the complete new value. Add User to Opal Group, Remove User from Opal Group, Request Group Access For User in Opal, and Approve Opal Access Request install with installer approval by default - someone must approve each run. Lookup and listing workflows run without approval by default. You can adjust approval settings after installation. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Opal Security integration. # OpenAI Source: https://docs.serval.com/sections/integrations/openai OpenAI powers Serval's built-in AI workflow actions - they work with zero setup, with nothing to connect. ## About OpenAI OpenAI is the model provider behind Serval's built-in text-generation workflow actions. Unlike most integrations, OpenAI is **not an application you connect** - the actions work out of the box and OpenAI never appears in the application connect list. **Authentication:** none required on Serval's hosted service - there is nothing to connect or configure. Self-hosted deployments install an OpenAI API key as part of setup; see [LLM / agent API keys](/sections/self-hosting/byoc-aws-prerequisites#llm--agent-api-keys). **Data sync:** none. OpenAI is called on demand when a workflow action runs - there is no entity sync, no member ingestion, no webhooks, and no polling. ## What the OpenAI integration enables | Capability | Description | | - | - | | **Prompt OpenAI** action | Single-prompt text generation in workflows. You provide a message (and optionally a model name) and the action returns the assistant's text. Defaults to the gpt-5.6-luna model. Preferred for single-turn prompts. | | **Create Chat Completion** action | Multi-message chat in workflows - include a system prompt and conversation history (and optionally a model name) and get back the assistant's reply. Defaults to the gpt-5.6-luna model. Use when a single message isn't enough. | ## Gotchas and troubleshooting This is by design - there is no Connect flow and no app instance for OpenAI. On Serval's hosted service the workflow actions work with zero setup. **Prompt OpenAI** and **Create Chat Completion** both default to gpt-5.6-luna, and both accept a different model name. This is separate from the models that Serval's own AI features use. The integration does not manage your OpenAI organization: no member provisioning, no usage reporting, no admin-key requirement. It is exactly two LLM workflow actions. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your OpenAI integration. # OpenPath Source: https://docs.serval.com/sections/integrations/openpath Connect Avigilon Alta (formerly Openpath) physical access control to Serval to automate door access, user credentials, and entry management through workflows. ## About OpenPath Avigilon Alta (formerly Openpath) is Motorola Solutions' cloud-based physical access control platform - doors, readers, mobile credentials, and entry management. The Serval integration appears in the app as "OpenPath" and connects using your Organization ID plus an admin email and password. Serval then proxies API calls to the Avigilon Alta API on behalf of your workflows, with all requests automatically scoped to your organization. Note the rebrand: the vendor now calls the product Avigilon Alta / Alta Access, and the legacy Openpath admin portal redirects to the Alta Access portal. **Authentication:** Organization ID plus admin email and password. Serval logs in to Avigilon Alta fresh on every API call and uses the returned session token automatically - there is no token caching. **Data sync:** On-demand only. There is no background sync, no webhooks, and no triggers - workflows call the Avigilon Alta API directly through a generic API request action. ## What the OpenPath integration enables | Capability | Description | | - | - | | Full OpenPath API access | Workflows use the "OpenPath API request" action to call any organization-scoped Avigilon Alta endpoint - users and their access credentials (mobile, card, and more), entries (the doors and access points in your organization), groups, and the rest of the organization-scoped API. Authentication and organization scoping are handled automatically, which makes this a natural fit for onboarding and offboarding workflows that grant and revoke door access. | | Connection health check | The built-in "List OpenPath Entries" health check verifies your stored credentials by logging in and listing the entries in your organization. | Anything in the [OpenPath API](https://openpath.readme.io/) that is scoped to your organization can be accessed through Serval. ## Get your credentials You need three things: your numeric Organization ID, and the email and password of a dedicated Avigilon Alta admin account without MFA. See the provider's guide to [authenticating with the API](https://openpath.readme.io/docs/using-the-api) for background. Go to the [Alta Access portal](https://access.alta.avigilon.com/). The legacy control.openpath.com URL redirects there. Read it from the browser URL: it is the number after "/o/". For example, if the URL contains "/o/302/dashboards/activityDashboard", your Organization ID is "302". It appears on every portal page. Create or designate a dedicated account for the integration - an Alta-native account with its own email and password, not a personal account and not an SSO-federated identity. Grant it the admin permissions your workflows need. Serval's login sends only the email and password and cannot supply a TOTP code. If MFA is required on the account, every API call will fail. The account must be Alta-native (created in the Alta Access portal) and must not have MFA enforced. SSO identities and MFA-protected accounts cannot be used for API access through this integration. Use a dedicated service account rather than a personal one. Because Serval logs in with the stored password on every call, a personal password change immediately breaks the integration. ## Connect in Serval In Serval, find the integration tile named "OpenPath" and open the connect form. All three fields are required and marked with an asterisk. Enter your numeric Organization ID from the portal URL. Helper text: "Your OpenPath organization ID (found in the OpenPath admin portal URL)". Leaving it blank shows "This field is required". There is no format validation, so a wrong ID is accepted at save time and only surfaces later as failed API calls. Enter the service account's email. Helper text: "Your OpenPath account email". Leaving it blank shows "This field is required". Enter the service account's password. Helper text: "Your OpenPath account password". The input is masked as you type. Submitting saves the credentials immediately - they are not tested against Avigilon Alta at save time. Run the health check right away to confirm connectivity. When you reopen the connection to edit it, Organization ID comes back in cleartext, Email comes back masked in an editable text box (bullet characters plus the last 4 characters), and Password shows the same masked format with a control to replace it. Fields you leave untouched or blank keep their stored values. To rotate a credential, enter the complete new value: clear the Email box and type the full new address, and for the Password use the replace control and type the full new password into the "Enter new value" box. Changing the Organization ID re-scopes all future API calls to the new organization. ## Verifying the connection The integration ships one health check: **List OpenPath Entries** - logs in to Avigilon Alta with the stored email and password, then lists the entries (doors and access points) in your organization to confirm the credentials and Organization ID work end to end. * On success: "Successfully connected to OpenPath and retrieved entries" * On failure: "Failed to list OpenPath entries. Please verify your email, password, and that MFA is disabled or a valid MFA code was provided." If the health check passes but a workflow call fails, the usual causes are: the service account lacks permission for that specific operation (the health check only needs to list entries), or the workflow's request path duplicates the organization scoping that Serval already adds automatically. ## Gotchas and troubleshooting Serval's login sends only an email and password; there is no field for a TOTP or MFA code anywhere in the integration. If the account has MFA enforced, every API call and the health check will fail with an authentication error. The health check's failure message mentions providing "a valid MFA code", but the integration has no way to supply one - the account must simply not require MFA. Avigilon's API documentation also requires an Alta-native account (not SSO) for API access. Session tokens are not cached: each proxied request logs in first, so every workflow API call generates two outbound requests to Avigilon Alta. Budget for this against provider rate limits on high-volume workflows. It also means a password change in Avigilon Alta breaks the integration instantly - the very next request fails - until the new password is entered in Serval. Submitting the connect form stores the credentials without testing them against the Avigilon Alta API. A typo in the Organization ID, email, or password is only caught when the health check or a workflow call runs. Always run the health check immediately after connecting or editing the connection. Serval bakes your Organization ID into the base of every API call, so workflow request paths must be relative to your organization - do not add the organization scoping to request paths yourself, or it will be applied twice. An incorrect Organization ID makes every call fail with a not-found or permission error even when the email and password are valid. On edit, Organization ID is shown in cleartext while Email and Password are shown masked - bullets plus the last 4 characters. A field you leave untouched or blank keeps its stored value, so you only ever need to fill in what you are changing. When rotating credentials, type the complete new value rather than editing the masked text: clear the Email box and type the full new address, or use the Password field's replace control and type the full new password. Then run the health check to confirm. Motorola Solutions rebranded Openpath as Avigilon Alta; the access product is "Alta Access". The Serval tile still says "OpenPath" and the API still lives at api.openpath.com, but the admin portal at control.openpath.com now redirects to the [Alta Access portal](https://access.alta.avigilon.com/), and provider docs use the Avigilon Alta name. If you are searching for "Avigilon" or "Alta", this is the integration you want. For provider-side issues, see [Avigilon Alta support](https://www.avigilon.com/support/openpath). *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your OpenPath integration. # Oracle Enterprise Manager Source: https://docs.serval.com/sections/integrations/oracle-em Connect Oracle Enterprise Manager target inventory to Serval. The Oracle Enterprise Manager integration reads database target inventory from a customer-hosted EM console. It supports the `oracle_database`, `rac_database`, and `oracle_pdb` target types and imports OEM target IDs and direct relationships as external assets. ## Beta requirements The full inventory workflow requires **Oracle Enterprise Manager 24ai Release 1 Update 12 (24.1.0.12) or newer**. Oracle introduced the relationship and membership APIs in that update; EM 13.5 and earlier 24.1 updates do not meet this workflow's requirements. See Oracle's [API change log](https://docs.oracle.com/en/enterprise-manager/cloud-control/enterprise-manager-cloud-control/24.1/emrest/APIOverview.html). This integration is in Beta. Confirm the exact update and complete a supervised inventory sync before scheduling it. Source-to-CMDB mapping requires validation against your Oracle data. ## Connect 1. Create an Enterprise Manager service account with **read-only** permission to the intended targets and their relationships. Validate access with this account; an administrator browser session does not verify the integration account. 2. Enter the HTTPS console URL, username, and password in Serval. Use the console host and port, for example `https://em.example.com:7802`. 3. If the console is on a private network, configure a worker that can reach it. The worker must trust the console's TLS certificate. 4. Run the connection, inventory, details/properties, and relationship health checks before enabling the inventory workflow. No visible database targets means inventory access has not been verified. The integration only sends GET requests to the target inventory API. It does not modify Oracle targets or incidents. ## Inventory sync Install **Oracle Database Inventory** to sync database, RAC, and PDB target snapshots. Each external asset is keyed by its OEM target GUID. The source data includes target details, properties, direct relationships, and RAC members. Review your EM instance's target types, cloud or non-cloud scope, source properties, and hierarchy before mapping these assets into CMDB classes. ## Troubleshooting * **Login page instead of JSON:** confirm the REST URL and that the EM account supports username/password API authentication through your console's authentication setup. * **401 or 403:** check the account credentials and target permissions. * **404 on relationships or members:** confirm Update 12 or newer, the target GUID and visibility. Oracle also uses 404 for resources the account cannot see. * **Network or certificate error:** check DNS, the console HTTPS port and the executing worker's CA trust. For private consoles, use [private network access](/sections/self-hosting/private-network-access). The workflow fails when a required topology request fails. It does not treat unavailable relationships as empty inventory. Validate RAC membership and repeat-sync identities during the pilot, and agree on missing-target handling before enabling a schedule. # Integrations Overview Source: https://docs.serval.com/sections/integrations/overview Connect your tech stack to Serval - browse the catalog, connect with the auth flow each app uses, verify with health checks, and manage everything from the Integrations page. ## Connect your entire tech stack Integrations are how Serval acts on the rest of your stack. A connected application can power ticket sync with your ITSM, mirror knowledge bases into Serval, sync users/groups/devices for access management and assets, and give workflows (and Catalyst) the ability to take real actions - provision access, manage devices, file tickets, query records. To browse what's available, open your team workspace and go to **Integrations → Connect new**. Search the catalog, or choose **Connect an app** to add a custom application. Install an integration in Serval Serval's Connect an application page showing the searchable catalog of integrations including Adobe, AWS, Confluence, Databricks, and more, each with Access and Workflows capability badges ## How connecting works Each integration uses the connection flow its provider supports. You'll see one of three patterns: * **Sign in with the provider (OAuth)** - a browser sign-in and consent screen, with no credentials to copy. Examples: [Confluence](/sections/integrations/confluence), [Jira](/sections/integrations/jira), [Notion](/sections/integrations/notion), [Microsoft 365](/sections/integrations/microsoft-graph). * **Guided app installs** - Serval walks you through installing an app on the provider side, like a [Slack](/sections/integrations/slack) app from a generated manifest, the Serval [GitHub](/sections/integrations/github) App, or the [Microsoft Teams](/sections/integrations/microsoft-teams) bot package. * **Credential forms** - you create a credential in the provider's admin console and paste it into Serval: API tokens ([Iru](/sections/integrations/iru), [Freshservice](/sections/integrations/freshservice), [Zendesk](/sections/integrations/zendesk)), OAuth client credentials ([Okta](/sections/integrations/okta), [Salesforce](/sections/integrations/salesforce), [ServiceNow](/sections/integrations/servicenow)), or service accounts ([Google Workspace](/sections/integrations/google-workspace), which also offers a basic Sign in with Google flow). Every integration's guide documents the exact provider-side click-path to create the credential, the fields Serval's connect form asks for, and the gotchas we see most often during setup. Secrets are stored encrypted and shown masked when you edit a connection later. ## Manage connected applications The **Integrations** page lists everything your team has connected, the capabilities each connection powers - Access, API, Knowledge, Ticket Sync, Workflows - and its connection status. Serval can also discover apps in use from your connected sources, so you can bring unmanaged software under management from the same page. Serval's Integrations page for a team showing connected applications with capability badges, resource counts, and green Connected status indicators ## Verify with health checks Most API-connected catalog integrations have an **API Integration** tab showing the scopes or permissions the connection was granted and a set of **health checks** that exercise the live integration - authentication, list/read access per surface, and write access where workflows need it. Run them right after connecting, and any time something stops working: a failing check names what it couldn't reach, which usually points straight at a missing scope or permission on the provider side. A few integrations don't include built-in health checks yet - their pages say so and suggest a quick manual verification instead. Okta application page in Serval showing the API Integration tab with current OAuth scopes and health checks for listing apps, groups, and users, each with a green status toggle When something is wrong, an alert icon appears on the integration's card on the **Integrations** page, in the app list, and in the sidebar, so you can spot a broken connection without opening each app. Hovering it shows how many **syncs** and how many **health checks** are currently failing as separate counts, each linking to where you investigate: the sync settings page for sync failures and the **API Integration** tab for health-check failures. The alert clears once the underlying syncs and checks recover. You can turn an individual health check off from its toggle. That choice is saved for that connected application, and a disabled check no longer runs or counts toward the integration's overall health. This lets you silence a check that doesn't apply to your setup without it showing the integration as unhealthy. ## Duplicate applications across teams You can copy a connected application's configuration to other teams in one click. Instead of configuring each team from scratch, open the application's **Settings** tab, find the **Duplicate Application** section, click **Duplicate**, and choose the destination team. ## Shared connections and self-hosted workers If a team receiving a shared connection is deleted, it disappears from the connection's sharing list. The remaining teams stay listed. If a shared connection uses **Run on self-hosted workers** (for example, Active Directory on-prem or a private-network app), the team receiving it needs its own self-hosted worker. Sharing the connection does not share the worker. See [Hybrid Worker Setup](/sections/self-hosting/deployment/hybrid-setup). ## Integration sync history Each application's **Settings** tab includes a **Sync History** view for monitoring background syncs: * **Track recent sync runs** - when each sync ran and its outcome * **View breakdowns** - how many items were added, updated, or removed * **Identify issues** - spot failed syncs and review error details to troubleshoot connectivity or permission problems ## Find your integration Each guide in this section covers one integration end to end: what it enables, where to get credentials on the provider side, the connect form in Serval, how to verify the connection, and the gotchas that actually come up. The most commonly connected: **Identity & directory:** [Okta](/sections/integrations/okta) · [Google Workspace](/sections/integrations/google-workspace) · [Microsoft 365 / Entra ID](/sections/integrations/microsoft-graph) · [LDAP / Active Directory](/sections/integrations/ldap-ad) **Messaging & collaboration:** [Slack](/sections/integrations/slack) · [Microsoft Teams](/sections/integrations/microsoft-teams) · [Confluence](/sections/integrations/confluence) · [GitBook](/sections/integrations/gitbook) · [Notion](/sections/integrations/notion) **ITSM & ticketing:** [ServiceNow](/sections/integrations/servicenow) · [Jira](/sections/integrations/jira) · [Zendesk](/sections/integrations/zendesk) · [Freshservice](/sections/integrations/freshservice) **Devices & assets:** [Iru](/sections/integrations/iru) · [Jamf](/sections/integrations/jamf) · [Apple Business Manager](/sections/integrations/apple-business-manager) **HR & business systems:** [Workday](/sections/integrations/workday) · [Salesforce](/sections/integrations/salesforce) · [NetSuite](/sections/integrations/netsuite) · [GitHub](/sections/integrations/github) Don't see your app? You can [connect a custom application](/sections/integrations/application) through Serval's API integration framework. # PagerDuty Source: https://docs.serval.com/sections/integrations/pagerduty PagerDuty is an incident response and on-call management platform - connect it to Serval so workflows can read and act on incidents, on-call schedules, and services through the PagerDuty REST API. ## About PagerDuty PagerDuty is an incident response and on-call management platform that helps teams detect, triage, and resolve critical issues. The Serval integration stores a PagerDuty REST API key for your account and lets workflows call any part of the PagerDuty REST API with authentication handled for you - workflow authors never see or handle the key. You can connect multiple PagerDuty accounts to the same team, each as its own connection. **Authentication:** a PagerDuty REST API key. A General Access REST API key (account-level) is the standard choice; a User Token REST API key also works but is limited to that one user's permissions. The key is stored encrypted and attached automatically to every request - and Serval only ever sends it to PagerDuty's own API host, api.pagerduty.com. **Data sync:** on demand. There is no background sync - Serval calls PagerDuty only when a workflow runs. ## What the PagerDuty integration enables | Capability | Description | | - | - | | Full API access | A single "PagerDuty API request" workflow action can reach any part of the PagerDuty REST API, with the API key injected automatically on every call. | | Incident management | Read, create, and update incidents, incident notes, and log entries. | | On-call and scheduling data | Look up who is currently on call, plus schedules, escalation policies, and teams. | | Services, users, and account data | List and inspect services, business services, users, tags, audit records, automation actions, alert grouping settings, add-ons, and analytics. | | Multiple instances | Connect more than one PagerDuty account, told apart by the auto-discovered subdomain and an optional Instance Name. | Anything defined in the [PagerDuty API](https://developer.pagerduty.com/api-reference/) can be accessed through Serval. ## Get your credentials You need a PagerDuty REST API key. PagerDuty offers two kinds that both work with Serval: a **General Access REST API key** (account-level - recommended) and a **User Token REST API key** (tied to one person and restricted to their permissions). See PagerDuty's guide to [API Access Keys](https://support.pagerduty.com/main/docs/api-access-keys) for details. Sign in to the PagerDuty web app as an Admin or the Account Owner - only those roles can create General Access REST API keys. (User Token keys can be created from your own profile, but only on accounts with PagerDuty's Advanced Permissions.) Navigate to **Integrations**, then **Developer Tools**, and select **API Access Keys**. Click **Create New API Key** and enter a **Description** that identifies it later, for example "Serval Production Integration". Leave **Read-only API Key** unchecked if your workflows will create or update anything in PagerDuty - a read-only key can only read data. Click **Create Key** and copy the value right away, then click **Close**. If you operate more than one PagerDuty account, confirm you are in the correct account/subdomain before creating the key. PagerDuty shows the key in full only once, at creation time. If you lose it, you cannot retrieve it - delete the key in PagerDuty and create a new one. The key must at minimum be able to read your account's teams - Serval validates the key by listing teams when you connect - and it needs read/write access matching whatever your workflows will do. Your PagerDuty account must contain at least one team the key can see. ## Connect in Serval In Serval, open the PagerDuty integration and start a new connection. The **Configure PagerDuty** dialog opens. Fill in **Instance Name (optional)**. The form describes it as: "A name to distinguish between different PagerDuty instances (e.g., 'Production PagerDuty')". If you leave it blank, the connection is named after your PagerDuty subdomain, which Serval discovers automatically. Paste the key into **API Key** (shown as a password field). The form does not flag this field as required, so there is no inline prompt if you forget it - an empty submission simply fails with the install error described in the gotchas below. Click **Submit**. Serval validates the key by reading your account's team list and derives your PagerDuty subdomain from the first team's web address. The subdomain identifies the connection (and names it, if you left Instance Name blank). If validation fails you will see "Failed to install integration (HTTP 500)" - see the gotchas below for what that usually means. **Editing an existing connection:** the saved key is shown as a locked, masked value - bullets plus its last 4 characters - with a **Replace** button next to it. Leaving it untouched keeps your stored key; this is safe and verified, and the same is true if you click **Replace** but submit with the field empty. Enter a new key only if you intend to rotate or replace it. The **Instance Name** field comes pre-filled with the current name - typing a new name renames the connection, but clearing it to blank keeps the existing name rather than resetting it. Failed updates show an error toast reading "Failed to update integration:". Entering a new API key on update re-derives the subdomain from that key. Pasting a key from a different PagerDuty account silently re-points the connection at that account. ## Verifying the connection PagerDuty connections don't currently include built-in health checks, so you won't see a health-check panel on this connection the way you do for some other integrations. The key is fully validated at connect time (Serval reads your team list), and you can confirm everything works after that: * Check that the connection appears with the expected name - your Instance Name, or your PagerDuty subdomain if you left it blank. The subdomain should match the account the key came from. * Run a workflow that reads PagerDuty data (for example, listing on-call responders) and confirm it returns results. If the connection looks healthy but specific workflow calls fail with permission errors, you are probably using a User Token key rather than a General Access key - user tokens are restricted to that one user's permissions and return a 403 for anything else. Switch to a General Access REST API key, or grant the token's user the needed access. ## Gotchas and troubleshooting The connect form gives no detail on failure. A generic failure at connect time almost always means one of: an invalid or revoked API key, an empty API Key field (the form does not catch this inline), or a PagerDuty account with no teams the key can read. Verify the key in PagerDuty and retry. Serval validates the key by reading the account's team list and derives your subdomain from the first team. If the key returns an empty team list, the connection cannot be created (the underlying error is "no teams found", though the UI shows only the generic install failure). Create at least one team in PagerDuty, and make sure the key can see it. Whenever you supply a new key on update, Serval re-derives the subdomain from that key and records it as the connection's identity. A key from a different PagerDuty account moves the connection to that account without warning. Double-check which account a replacement key belongs to. On the edit form the key shows as bullets plus its last 4 characters, with a Replace button. Leaving it untouched - or clicking Replace and submitting nothing - keeps the stored key unchanged; this behavior is verified safe. Only a non-empty new value replaces the key. A General Access key created with the Read-only API Key option connects successfully (Serval's validation only reads data), but any workflow step that creates or updates something in PagerDuty will be rejected. Use a full-access key if workflows need to act on incidents. PagerDuty results are paginated with offset-based paging, and Serval ships no PagerDuty-specific pagination helpers - workflows must loop through pages themselves, typically 100 records at a time. Requests are typed against [PagerDuty's official API schema](https://github.com/PagerDuty/api-schema), so an invalid path is caught when the workflow code is type-checked rather than at runtime. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your PagerDuty integration. # Palo Alto Strata Cloud Manager Source: https://docs.serval.com/sections/integrations/palo-alto-strata-cloud-manager Strata Cloud Manager is the cloud management plane for Palo Alto Networks firewalls, Prisma Access, and SD-WAN - Serval connects to one tenant with an IAM service account so workflows can inventory devices and read or change security configuration. ## About Palo Alto Strata Cloud Manager Strata Cloud Manager is the cloud management plane for Palo Alto Networks NGFWs, Prisma Access, and SD-WAN. Serval connects to a single Strata Cloud Manager tenant using a Palo Alto Networks IAM service account, and once connected, workflows read the tenant's device inventory and configuration hierarchy, manage policy objects and security rules, and push configuration changes out to the firewalls. **Authentication:** OAuth 2.0 client credentials (a Palo Alto Networks IAM service account). Serval exchanges the stored Client ID and Client Secret for short-lived access tokens scoped to your Tenant Service Group, automatically - there is no browser redirect and no per-user sign-in. **Data sync:** two optional ingestion workflows sync devices and folders into Serval as external assets. Everything else runs on demand: workflows call the live Strata Cloud Manager API when they run. ## What the Strata Cloud Manager integration enables | Capability | Description | | - | - | | Device inventory | List every firewall and appliance the tenant manages, with hostname, IPv4/IPv6 and MAC addresses, model, product family, software and content versions, HA state, connection status, and installed licenses - the source data for CMDB and asset-reconciliation workflows. | | Configuration hierarchy | Read the folders, labels, snippets, and variables that devices are organized into, plus the sites and site groups used for SD-WAN device onboarding. | | Network configuration | Read the interfaces (ethernet, aggregate, VLAN, loopback, tunnel, and subinterfaces), security zones, logical routers, IKE gateways and IPsec tunnels, BGP profiles and route maps, NAT and PBF rules, and QoS settings a firewall is configured with. | | SD-WAN and deployment topology | Read the SD-WAN rules, path-quality, traffic-distribution and error-correction profiles, link tags, and AutoVPN clusters, plus the remote networks, service connections, bandwidth allocations, BGP routing, and physical sites that make up a Prisma Access deployment. | | Policy objects | Create, read, update, and delete address objects and groups, services, tags, applications, regions, schedules, dynamic user groups, external dynamic lists, and log-forwarding and server profiles. | | Security rules and profiles | Read and change security, decryption, DoS-protection, and app-override rules (including reordering them), along with the anti-spyware, URL-filtering, WildFire, file-blocking, and vulnerability-protection profiles they reference. | | Configuration push | Push the candidate configuration to the tenant's devices and track the resulting job to completion. | | Operational reads | Pull a device's running configuration, and run route-table, FIB, DNS-proxy, interface, and rule-status jobs against a device for troubleshooting workflows. | | Generic API access | Call any of these endpoints through Serval's Strata Cloud Manager API request action - 263 typed endpoint paths across configuration setup, device onboarding, network services, network deployment, objects, security services, config operations, and troubleshooting. | Anything defined in the [Strata Cloud Manager API](https://pan.dev/scm/api/) on `api.strata.paloaltonetworks.com` can be accessed through Serval. ## Get your credentials Serval needs a **service account** created in Strata Cloud Manager, and the **TSG ID** of the tenant it should manage. See Palo Alto Networks' [service accounts documentation](https://pan.dev/scm/docs/service-accounts/) for full details. In the left panel, go to **Settings > Identity & Access**. The Tenant Service Group ID is shown at the top of the Identity & Access page, next to the tenant name. It is numeric. Confirm it belongs to the tenant you want Serval to manage - a service account can be entitled to several. Add a new identity, choose **Service Account** as the identity type, name it (for example, "Serval Integration"), and continue. Download and save the credentials file. It contains the Client ID and Client Secret. Give the service account a role on this tenant. Read-only roles are enough for inventory and reporting workflows; workflows that create objects, change rules, or push configuration need a role that grants those permissions. The Client Secret is available **only** in the credentials file downloaded at creation, and cannot be retrieved later. Save it before leaving the page - if you lose it, generate a new secret (or a new service account) in Strata Cloud Manager. ## Connect in Serval In Serval, open the Palo Alto Strata Cloud Manager integration and start a new connection. The numeric Tenant Service Group ID from the step above. A non-numeric value is rejected with "TSG ID must be the numeric Tenant Service Group ID shown in Strata Cloud Manager". The service account's Client ID, which looks like `name@1234567890.iam.panserviceaccount.com`. The service account's Client Secret (a password field). Submit the form, then run the health checks below to confirm the credentials and the role assignment are both right. The TSG ID is part of the connection's identity, so one Serval team can connect several Strata Cloud Manager tenants - each with its own TSG ID - without them colliding. Reconnecting with the same TSG ID updates the existing connection. When editing an existing connection, the Client Secret displays obfuscated. Leaving it unmodified keeps the stored secret - you only need to fill in the fields you are rotating. ## Verifying the connection The integration ships four health checks: * **Validate API connection** - reads a single folder, confirming the token exchange works and the service account has a role on this tenant. * **List devices** - confirms the connection can read the tenant's device inventory. * **List folders** - reads the configuration hierarchy the devices are organized into. * **List address objects** - reads the address objects in the **Shared** folder, confirming the service account's role reaches the objects API and not only the setup API. All four checks can pass while a workflow still fails with a permission error - the checks only exercise reads. Any workflow that creates objects, edits rules, or pushes configuration needs a Strata Cloud Manager role that permits those actions. ## Syncing devices into Serval Two installable ingestion workflows are available: * **Ingest Devices from Palo Alto Strata Cloud Manager** - syncs the managed firewalls and appliances as external assets, carrying the full device record (hostname, addresses, model, family, software and content versions, HA state, licenses). * **Ingest Folders from Palo Alto Strata Cloud Manager** - syncs the folder hierarchy, including each folder's parent and labels. Both page through the tenant and are safe to schedule. Devices reference their folder by name, so ingesting folders alongside devices is what makes the location and grouping resolvable. ## Gotchas and troubleshooting Strata Cloud Manager scopes every access token to a Tenant Service Group. A valid Client ID and Secret paired with a TSG the service account is not entitled to fails at the token exchange, which surfaces the same way a bad secret does. Re-check the TSG ID at the top of the Identity & Access page in the tenant you intend to manage. Permissions come from the role assigned to the service account in Strata Cloud Manager, not from anything stored in Serval. A read-only role passes the setup health checks and then fails a workflow that writes. Grant the role the workflow needs on the tenant. The objects, security-services, and network-services endpoints require exactly one of `folder`, `snippet`, or `device` as a query parameter and answer 400 without one, even though the API reference marks them optional; the deployment endpoints declare `folder` required outright. Pass `folder: "Shared"` (or the specific folder you mean) for a spot read. A workflow that wants the whole tenant has to list folders first and repeat the read for each one - only the device list and AutoVPN clusters are flat, tenant-wide collections. Security rule reads additionally require `position`, which is either `pre` or `post`. `/config/network/v1` describes how interfaces, zones, routers, and tunnels are configured, which is not the same as what a firewall is doing right now. An interface's addresses live at `layer3.ip[].name` and only on the static variant, so a DHCP-addressed interface has no address there at all. Live interface status, the real route table, and the FIB come only from the `/operations/v1/jobs/*` endpoints, which are asynchronous per-device jobs you submit and then poll - workable for a single device in a troubleshooting workflow, impractical for bulk inventory. Creating or editing an object or a rule only changes the tenant's candidate configuration. It reaches the firewalls when the candidate configuration is pushed, which returns a job - poll that job until it completes before treating the change as live. A workflow that writes and then stops has not changed anything on the network. This connection is pinned to `api.strata.paloaltonetworks.com`. Palo Alto Networks also serves parts of this API from `api.sase.paloaltonetworks.com` under different paths, and the tenancy, subscription, and licensing APIs live only there - none of those are reachable through this integration. The device record's `id` field is described as a UUID in the API reference; hardware firewalls report their serial number there. The ingestion workflow keys assets on `id` without depending on which it is, and forwards the whole device record so a downstream mapping can pick whichever identifier your CMDB expects. Strata Cloud Manager enforces API rate limits per tenant. Prefer paged collection reads over one call per resource, and keep scheduled workflows on a modest interval - see Palo Alto Networks' [API best practices](https://pan.dev/scm/docs/api-best-practices/). *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Palo Alto Strata Cloud Manager integration. # PandaDoc Source: https://docs.serval.com/sections/integrations/pandadoc Connect PandaDoc to Serval with a workspace API key so workflows can create, send, and track documents, templates, contacts, and anything else in the PandaDoc API. ## About PandaDoc PandaDoc is a document automation and e-signature platform for contracts, proposals, and other business documents. Serval connects to a PandaDoc workspace with a single API key: an admin pastes it in once, Serval stores it encrypted for your team, and workflows call PandaDoc on demand with that key attached. Serval only ever sends the key to one host for this integration: api.pandadoc.com. **Authentication:** API key (a PandaDoc workspace API key). There is no OAuth sign-in flow, and the key never expires on a schedule - it works until you revoke or rotate it in PandaDoc. **Data sync:** None. Nothing is imported into Serval in the background - PandaDoc is called only when a workflow runs. ## What the PandaDoc integration enables | Capability | Description | | - | - | | Full document lifecycle from workflows | Create documents, send them for signature, track status, read details and audit trails, download finished copies, and manage recipients, attachments, and fields. | | Work with the rest of the PandaDoc API | Templates and template folders, content library items, contacts, workspace members and users, webhook subscriptions, forms, quotes, product catalog items, notarization requests, and more. | | AI-ready API definitions | Serval's connector is built from PandaDoc's official API definitions, so Serval AI can author accurate workflow steps against PandaDoc for you. | | Multiple workspaces side by side | Each connection is identified by its Instance Name, so you can connect several PandaDoc workspaces and have workflows target one of them or all of them. | Anything defined in the [PandaDoc API](https://developers.pandadoc.com/reference/about) can be accessed through Serval. ## Get your credentials Serval needs a PandaDoc **API key** for the workspace you want it to operate in, created by a user with admin access to that workspace's API settings. PandaDoc's official guide is here: [API key authentication process](https://developers.pandadoc.com/reference/api-key-authentication-process). In PandaDoc, click the **gear icon** (Settings) in the bottom left corner. Under your current workspace, click **API and Integrations**. Scroll to the **API and Webhooks** section. Click the **API** tile, then click **Open**. Copy the **API Key** and store it securely - you will paste it into Serval. Use a **production** key for live use. PandaDoc also issues sandbox keys, and a sandbox key only works against sandbox data - workflows pointed at your real documents will fail with one. API keys are scoped to a single PandaDoc workspace. If Serval should work across more than one workspace, create a key in each and connect each one separately. ## Connect in Serval Find the app in your Serval integrations catalog and click Connect. It's listed as **Pandadoc** - that exact spelling, with a lowercase "d". The **Instance Name** field is a plain text field. It isn't marked required on the form, but it becomes the connection's display name and internal identifier, so always fill it in - and if you plan to connect more than one workspace, give each a distinct name. The **API Key** field is a password field. Paste the full key exactly as PandaDoc shows it. Click **Submit**. If installation fails, the form shows "Failed to install integration" along with the underlying error. Serval does not test the key against PandaDoc when you connect, and this integration has no automated health checks - a mistyped or revoked key is accepted and only fails later, the first time a workflow calls PandaDoc. Verify the connection right after saving (see below). When you edit an existing connection, the stored key appears masked - bullets plus its last 4 characters. On the connection's settings page, a pencil icon swaps in a replacement box (its placeholder reads "Enter new value"); in the reconnect dialog, the masked value sits next to a **Replace** button. Leaving the masked value untouched - or saving with the replacement box empty - keeps your existing key, so you can safely change just the Instance Name. To rotate the key, paste the complete new key and save. ## Verifying the connection The PandaDoc integration has no automated health checks in Serval, so nothing runs after you connect and there is no pass/fail status to look for. To verify the connection: 1. Create or run a simple workflow step that reads PandaDoc data - for example, one that lists your documents or templates. 2. If the step returns PandaDoc data, the key works. 3. If it fails with an authentication error, copy the API key from PandaDoc again and replace it in the connection settings. If a basic read works but a workflow can't find a specific document or template, the item most likely lives in a different PandaDoc workspace (keys are workspace-scoped), or you connected a sandbox key while the data lives in production. ## Gotchas and troubleshooting No call is made to PandaDoc when you save the connect form, so a bad key is stored without complaint, and there is no health check to catch it afterward. The failure only appears the first time a workflow calls PandaDoc. Make a quick test workflow part of your connect routine. On the connection's settings page the key is shown masked (bullets plus its last 4 characters) with a pencil icon to replace it; the reconnect dialog shows the same masked value with a **Replace** button. Leaving the masked value untouched keeps the existing stored key - renaming the connection never requires re-entering the key - and so does saving with the replacement box left empty. To rotate, enter the entire new key and save. If an update fails, Serval shows a message starting with "Failed to update integration:" or the message "Failed to update configuration", depending on which form you used. The Instance Name doubles as the connection's display name and internal identifier. Saving an update with the name emptied out is rejected and surfaces as a generic update failure. Renaming does work, but it also changes the internal identifier, so workflows pinned to this specific PandaDoc connection may need to be re-pointed afterward. Pick a clear, distinct name when you connect - especially if you connect multiple PandaDoc workspaces. PandaDoc issues both production and sandbox API keys. A sandbox key connects without error but can only reach sandbox documents and templates, so workflows against your real workspace data will fail. Use a production key for live use. PandaDoc returns list results (documents, templates, contacts, and so on) one page at a time. Workflows have to ask for the next page until an empty page comes back - if a workflow seems to be missing items, it's usually only reading the first page. Serval AI handles this when it authors the workflow, but it's worth checking if results look incomplete. Serval authenticates to PandaDoc using PandaDoc's "API-Key" authorization scheme, not the more common "Bearer" scheme. If you sanity-check the same key with another tool and use Bearer, PandaDoc rejects it even though the key is fine in Serval. Serval also only ever attaches the key to requests bound for api.pandadoc.com. This connector does not import PandaDoc users, documents, or anything else into Serval, and it has no access-management features. If you've seen older Serval documentation listing an "Access Management" capability for PandaDoc, that does not apply to the current integration - user and permission changes in PandaDoc are only possible as ordinary workflow API calls. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your PandaDoc integration. # Palo Alto Panorama Source: https://docs.serval.com/sections/integrations/panorama Discover managed firewalls and call Panorama XML and REST APIs. The Panorama integration connects workflows to the Panorama XML and REST APIs. Use it to discover managed firewalls, read or change configuration, manage policies and objects, commit changes, run operational commands, and import or export files. This is separate from the Strata Cloud Manager integration. ## Requirements * A Panorama hostname or IPv4 address reachable over HTTPS on port 443. * A trusted TLS certificate matching that hostname. * An API key for a dedicated Panorama administrator with permissions for the operations and devices your workflows need. For inventory-only workflows, use read-only permissions. Custom XML API operational permissions can also allow changes, so validate the role against your Panorama version. Generate the key following Palo Alto's [API authentication documentation](https://docs.paloaltonetworks.com/ngfw/api/api-authentication-and-security). Connection setup takes the resulting key. Serval sends it in the `X-PAN-KEY` header to the configured instance. The integration can perform writes when the account permits them; configure workflow approvals and account permissions for your intended use. ## Connect 1. Open **Integrations**, select **Palo Alto Panorama**, and choose **Connect**. 2. Enter the Panorama hostname without `https://`, a port, or a path. 3. Enter the API key and save the connection. 4. Run the connection and firewall-list health checks. Reconnect to rotate the key. Changing the hostname requires a new key. For internal endpoints, arrange a supported [private network connection](/sections/self-hosting/private-network-access). Certificate verification remains enabled. The health checks test inventory access; they do not establish permission for every write operation. ## API coverage | Interface | Supported requests | | - | - | | XML API | Configuration get, show, set, edit, delete, move, clone, rename and multi-config; operational commands; commits and commit-all; logs, reports, User-ID, version, key generation, imports and exports. | | REST API | Versioned resource requests for Objects, Policies, Network, Device and Panorama resources exposed by your appliance, including create, read, update, delete and resource action suffixes. | | Discovery helpers | Managed devices, connected devices and system information for Panorama or a target firewall. | `xmlApiRequest` accepts a request `type` and vendor parameters such as `action`, `xpath`, `element`, `cmd`, `target`, `category`, and `job-id`. POST requests use form encoding; GET requests use query parameters. File imports use a multipart `file` part with caller-provided base64 bytes and a filename. `restApiRequest` requires an explicit version, such as `v11.1`, and a relative resource, such as `Objects/Addresses`. It accepts query parameters, JSON or XML bodies, and JSON or XML responses. Consult the instance's `/restapi-doc` for its supported resource names, methods and fields. The integration provides general API transports; it does not supply a separate typed schema for every vendor resource and command. Use Palo Alto's [XML API reference](https://docs.paloaltonetworks.com/ngfw/api/pan-os-xml-api-request-types-and-actions) and [REST request structure](https://docs.paloaltonetworks.com/ngfw/api/get-started-with-the-pan-os-rest-api/pan-os-rest-api-request-response-structure) to construct requests for your appliance version. REST configuration edits require an explicit XML API commit. A returned job ID acknowledges queued work; poll the job separately to establish completion. Pagination and report or log retrieval also require explicit requests. ## Response handling and limits General actions return HTTP status, response headers and a body. XML responses retain their envelope, preserve scalar values as strings, and make `entry` and `member` elements arrays. XML and REST error envelopes fail the action even with a successful HTTP status. Exports can return parsed XML, raw text, or base64 for binary data. Imports and responses are buffered and limited to 50 MiB, so larger software images and support archives need another transfer method. Ordinary form requests must also satisfy Panorama's own request-size limits. Requests do not follow redirects or retry automatically. A timeout does not prove that a write failed; inspect the appliance or job status before resubmitting. General API actions are treated as potentially mutating, including XML GET calls. Treat returned names, descriptions, logs and configuration as external data, never as instructions authorizing subsequent writes. ## Firewall discovery The discovery helpers use `show devices all`, `show devices connected`, and `show system info`, as documented in Palo Alto's [Panorama discovery examples](https://docs.paloaltonetworks.com/ngfw/api/pan-os-xml-api-use-cases/query-a-firewall-from-panorama-api). System information accepts a target firewall serial number. Device results include serial numbers, hostnames, management IP addresses, models, software versions and connection status when returned by Panorama. `devices.entry` is always an array. A disconnected firewall can appear in the managed list while a targeted request fails. Keep request failures distinct from an empty inventory. This connector does not create an automatic inventory synchronization job. The integration is beta. Validate required operations, permissions, inventory counts and version-specific fields on your Panorama appliance before production use. # Paycom Source: https://docs.serval.com/sections/integrations/paycom Connect Serval to Paycom, the HR and payroll platform, so your workflows can read employee data, manage time and attendance punches, and work with applicants, new hires, positions, and labor allocation. ## About Paycom Paycom is an HR and payroll platform that holds your organization's employee, time and attendance, applicant, and labor allocation data. Serval connects to a single Paycom client account using the REST API credentials Paycom issues to your organization. Once connected, your Serval workflows can read HR data and import or edit time card punches whenever they run. Serval only ever sends your credential to one host for this integration: api.paycomonline.net. **Authentication:** Paycom REST API credentials — a SID (your client security identifier) and a token, stored together as one credential and sent as HTTP Basic auth. There is no OAuth flow. **Data sync:** On-demand only. Workflows call the Paycom API at the moment they run. There is no background sync, no data ingestion, no webhooks, and no event triggers. Paycom only accepts API requests from IP addresses that are allowlisted for your client account. Before connecting, ask your Paycom specialist to allowlist the addresses Serval calls Paycom from — contact [support@serval.com](mailto:support@serval.com) for the current list of Serval egress IPs. If your organization cannot allowlist Serval's IPs, the connection can instead be routed through a Serval self-hosted worker running inside a network whose egress IP Paycom already trusts; contact [support@serval.com](mailto:support@serval.com) to set this up. ## What the Paycom integration enables | Capability | Description | | - | - | | Employee data | Read the employee directory, full employee master records, and (where your credential permits) sensitive data such as pay rates, tax setup, and deposit distributions. Look up employees by their four-character employee code. | | Employee changes | List employees whose records changed in a time window and read the specific changes, including custom-field and sensitive-data change histories — useful for building sync workflows. | | Time and attendance | Import punches, hours, or earnings to employee time cards in real time; edit or delete existing punches; read punch history, punch audit trails, and live clocked-in/out status. | | Applicants and new hires | Read applicant tracking (ATS) data — applications, statuses, workflow steps — and new hire records, photos, and custom fields. | | Positions | Read position details, levels, and seats from Position Management. | | Labor allocation | Read and manage labor allocation profiles, categories, and distribution details, including bulk additions. | | Company setup | Read company establishments, locations, and earning codes. | | Full Paycom REST API access | Workflows are not limited to the capabilities above — they can reach any Paycom REST API endpoint your credential is permitted to use. | Anything in the Paycom REST API can be accessed through Serval. ## Get your credentials Paycom issues REST API credentials per client. There is no self-service developer portal — credentials are provisioned by Paycom for your account. Ask your Paycom dedicated specialist or client representative to enable the REST API for your client account and to create an API service user. They will issue you a SID (client security identifier) and a token. Ask your Paycom specialist to allowlist the IP addresses Serval will call Paycom from. Contact [support@serval.com](mailto:support@serval.com) to get the current list of Serval egress IPs. Requests from IPs that are not allowlisted fail to authenticate even with valid credentials. If you cannot allowlist Serval's IPs, contact [support@serval.com](mailto:support@serval.com) about routing this connection through a self-hosted worker instead. In Serval, add the Paycom integration and enter your SID and token. Serval encodes them as HTTP Basic auth automatically — you do not need to base64-encode anything yourself. ## Rate limits Paycom enforces per-endpoint rate limits (calls per second and calls per day); each endpoint's limits are documented on its operation in the Serval workflow builder. Most read endpoints allow 10 calls per second; punch-import writes allow 3 calls per second. List endpoints paginate with `page` (starting at 1) and `pagesize` (default 25, maximum 500) parameters. ## Security notes * Your SID and token are stored encrypted and injected into requests server-side. Workflow authors and workflow code never see the credential. * Serval only injects the credential toward api.paycomonline.net. * Read access to sensitive employee data (pay rates, tax details, deposit accounts, SSNs) is controlled by the permissions Paycom grants your API service user — scope it to only what your workflows need. # Persona Source: https://docs.serval.com/sections/integrations/persona Persona is an identity verification and compliance platform (KYC/KYB, fraud prevention) - connect it with an API key so Serval workflows can call any part of the Persona API on demand. ## About Persona Persona is an identity verification and compliance platform used for KYC and KYB checks and fraud prevention. The Serval integration connects to your Persona organization with an API key and gives workflows on-demand access to the entire Persona API through a single "Persona API request" action. The key is only ever sent to Persona's official API address (api.withpersona.com), and Serval pins Persona API version 2025-10-27 on every request, so workflow behavior stays consistent regardless of your key's default version. **Authentication:** API key (created in the Persona Dashboard) **Data sync:** On demand only - no background sync, no scheduled imports, and no pre-installed workflows. Persona is called only when a workflow runs the "Persona API request" action. ## What the Persona integration enables | Capability | Description | | - | - | | Persona API request | A single workflow action with typed access to the entire Persona REST API - 176 operations generated from Persona's official API specification. | | Identity verification | Create, retrieve, update, resume, approve, and decline identity verification inquiries, manage inquiry sessions, and read inquiry templates. | | Account management | List, create, update, tag, and consolidate accounts, including permanent PII redaction of an account and its associated inquiries, verifications, and reports (GDPR/CCPA compliance). | | Compliance and fraud data | Read and manage verifications, reports, cases, transactions, devices, documents, events, importers, user audit logs, and API logs. | | Lists, webhooks, and workflows | Manage block/allow lists and list items, manage webhook subscriptions, trigger Persona workflows, and read workflow runs. | Anything defined in the [Persona API](https://docs.withpersona.com/api-reference/) can be accessed through Serval. ## Get your credentials You need an organization API key from the Persona Dashboard. Sandbox keys start with `persona_sandbox` and production keys start with `persona_production`. For background, see the [Persona API reference](https://docs.withpersona.com/api-reference/). Go to the [Persona Dashboard](https://app.withpersona.com) and sign in. Navigate to **API**, then **API Keys**. Click **Create API key**. When asked for the API version, select **2025-10-27** - Serval sends this version on every request (see [Persona API versioning](https://docs.withpersona.com/versioning)), so choosing it keeps your key's settings aligned with what workflows actually see. Persona API keys have full permissions until you explicitly configure restrictions. Consider restricting the key to only what your workflows need. Persona shows the full key only once. Copy it right away - if you lose it, you will need to create a new key. Sandbox and production are separate keys, not separate settings. If you use both environments, create one key per environment and connect each one to Serval as its own connection. ## Connect in Serval In Serval, open the **Persona** integration and start a new connection. The **Configure Persona** dialog opens with two fields. A friendly display name for the connection. The helper text reads: "A friendly name for this Persona integration (e.g., 'Production', 'Staging')". Leaving it blank shows "This field is required". Paste the full key you copied from the Persona Dashboard. It is a password field, so the value is hidden as you type. The helper text reads: "Your Persona API key (starts with persona\_sandbox or persona\_production)". The field is marked with an asterisk, but the form does not actually block saving when it is left blank - paste carefully. Click **Submit**. Serval does not test the key when you save - a mistyped, blank, or revoked key is only caught the first time a workflow calls Persona. If the save itself fails you will see a general error such as "Failed to install integration". After saving, the key is shown masked - bullet characters plus its last 4 characters - and can be replaced later but never viewed in full. When editing an existing Persona connection - even just to rename it - always replace the API key in the same save: select the pencil icon (or **Replace** button) next to the masked value, paste the complete API key, keep the Instance Name filled in, and save in one step. Do not save while the key field is blank or still showing only its masked value. After saving, run a workflow that calls Persona to confirm the connection still works. Follow the same routine when rotating the key. ## Verifying the connection This integration has no built-in health checks, and the key is not validated when you connect. To verify the connection, run a workflow that uses the "Persona API request" action - for example, one that lists recent inquiries - and confirm it returns data. An invalid or revoked key shows up as a failed request - typically an authorization error from Persona. If requests succeed but you cannot find the records you expect, check which environment the key belongs to: keys starting with `persona_sandbox` only see sandbox data, and keys starting with `persona_production` only see production data. The Instance Name is just a label - the key determines the environment. ## Gotchas and troubleshooting Saving the edit form without re-entering the API key can break the connection. Whenever you edit a Persona connection - even just to rename it - select the pencil icon (or **Replace** button) next to the masked key, paste the complete API key, save, and then run a workflow call to confirm it still works. Errors during the edit itself appear as "Failed to update configuration". Serval does not test the key at connect time and runs no recurring health checks, so a wrong, restricted, or revoked key surfaces only when a workflow's Persona API request fails (typically with an authorization error from Persona). If you suspect the key, create a fresh one in the Persona Dashboard and replace it in Serval. The [Persona Help Center](https://help.withpersona.com/) covers managing keys on the Persona side. Every request Serval sends uses Persona API version 2025-10-27, overriding the key's default version. Request and response shapes in workflows follow that version - see [Persona API versioning](https://docs.withpersona.com/versioning) if your team relies on a different version elsewhere. Both environments are reached the same way - only the key (its `persona_sandbox` or `persona_production` prefix) determines which environment a connection talks to. Use the Instance Name to label the environment clearly, and connect sandbox and production as separate connections. Persona wraps every record in a standard envelope: the useful fields live under `data.attributes`, not at the top level, and lists come back as a `data` array. If a workflow builder reports "missing" fields, this nesting is the usual cause. Serval attaches your API key only to requests going to api.withpersona.com. The Persona API request action targets that address automatically, and the credential is never sent anywhere else. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Persona integration. # PingID Source: https://docs.serval.com/sections/integrations/pingid Connect Serval to PingOne so workflows can manage users, groups, passwords, sessions, and MFA devices in Ping Identity's cloud IdP. ## About PingID PingID (PingOne) is Ping Identity's cloud identity platform. The Serval PingID integration connects to your PingOne environment using a **worker application** with OAuth 2.0 client credentials. Workflows can manage the full identity lifecycle — look up, create, enable, disable, unlock, and delete users, reset passwords, revoke sessions, manage group membership — plus MFA devices, and call PingOne Management and MFA APIs with typed request schemas. The integration is marked **Beta** in Serval's connect UI. **Authentication:** OAuth 2.0 client credentials against your PingOne environment. Serval exchanges the Client ID and Client Secret for short-lived bearer tokens at `https://auth.{region}/{environmentId}/as/token` and attaches them to API requests at `https://api.{region}`. **Data sync:** Background sync keeps Serval's user directory, group catalog (with memberships), and application catalog current with the PingOne environment. Users support changed-since delta syncs via PingOne's `updatedAt` filter; groups re-walk in full on a schedule because PingOne exposes no group change feed. ## What the PingID integration enables | Capability | Description | | - | - | | User Lifecycle bundle | Prebuilt workflows: get user details (profile, enabled state, lock status, group names, last sign-on), create a user, enable/disable, unlock a locked account, set a temporary password with forced change, email a password recovery code, revoke all sessions, and delete a user. | | Group Management bundle | Prebuilt workflows: list groups, list a group's members, review a user's memberships, and add or remove a user from a group by name. | | MFA Management bundle | Prebuilt workflows: list a user's MFA devices, add an SMS device, activate a pending device with an OTP, unpair one device, and reset all MFA devices for a user. | | User sync | Background ingestion of PingOne users (profile, enabled state, manager/department/title attributes) into Serval's directory, with changed-since delta syncs and targeted single-user refresh. | | Group sync | Background ingestion of PingOne groups and their memberships as Serval resources with a Member entitlement, plus name lookup for linking. | | App sync | Background ingestion of PingOne applications (name, icon, enabled state) and their group-based access-control restrictions, powering the app catalog. Machine-credential apps (Worker/Service types) are excluded. | | Access provisioning | PingOne group membership backs Serval access-management provisioning: granting access adds the user to the linked PingOne group, revoking removes them, both idempotently. | | PingID API request | Typed identity and MFA operations from the hand-authored PingOne spec, including the vendor media types PingOne uses to select same-endpoint actions (account unlock, password set, recovery codes, user import). | | PingOne API discovery | Full PingOne Management and MFA endpoint catalogs are indexed for workflow authoring, even when request bodies are untyped in the broader specs. | Mutating workflows ship with **installer approval** by default; read-only lookups and the self-service recovery-code email run without approval. ## Get your credentials You need your PingOne **Environment ID**, a **worker application** Client ID and Client Secret, and the **region** that hosts your environment. Sign in to the PingOne admin console for your organization. Go to **Settings → Environment Properties** and copy the Environment ID (a UUID). Under **Connections → Applications**, create a **Worker** application (or reuse an existing one). Assign roles that include **Identity Data Admin** for this environment — it covers the user, group, password, and session operations, and the MFA device workflows. From the worker application's **Overview** tab, copy the Client ID and Client Secret. Select the PingOne region that matches your environment: North America (`api.pingone.com`), Canada (`api.pingone.ca`), Europe (`api.pingone.eu`), Asia-Pacific (`api.pingone.asia`), Australia (`api.pingone.com.au`), or Singapore (`api.pingone.sg`). Worker applications are machine credentials with broad API access. Restrict the application's roles to the smallest set that covers your Serval workflows. ## Connect in Serval In Serval, add the PingID integration. It is labeled **Beta**. Select the PingOne API domain for your environment. Paste the UUID from Environment Properties. Paste the worker application's Client ID. Paste the worker application's Client Secret in the password field. Submit the form. Serval runs the health checks below. When editing an existing connection, blank or obfuscated fields keep their stored values. Paste a new Client Secret to rotate credentials without re-entering the Environment ID. ## Verifying the connection Five health checks cover the integration: 1. **Test PingID Connection** — reads the environment record. Success: `Successfully authenticated with PingOne`. Failure includes region- or credential-specific guidance from the integration. 2. **List PingOne Users** — fetches one user from `/environments/{environmentID}/users`. Confirms Identity Data read access. 3. **List PingOne Populations** — reads populations in the environment. Confirms directory read access beyond authentication alone. 4. **List PingOne Groups** — fetches one group. Confirms the read access the group workflows depend on. 5. **Manage PingOne Groups** — creates and immediately deletes a `serval-healthcheck-` prefixed group. Confirms the write access used by group management and access provisioning. This is a write check; if the delete fails, the check names the leftover group so you can remove it in the PingOne console. If the connection test passes but user, population, or group checks fail, the worker application authenticates but lacks Identity Data Admin (or equivalent) permissions. Adjust the application's role assignment in PingOne. ## Gotchas and troubleshooting Serval uses the client-credentials grant. Browser-based or authorization-code applications will not exchange tokens the way this integration expects. A North America Client ID against an EU environment (or mismatched Environment ID) fails token exchange before any workflow runs. **Delete PingOne User** is permanent and removes group memberships and MFA devices with the account. **Disable PingOne User** blocks sign-on reversibly and is the right default during offboarding. Disabling does not revoke existing sessions — pair it with **Revoke PingOne User Sessions**. **Send PingOne Password Recovery Code** only works when the environment's password policy has recovery enabled and the user has an email address. Otherwise use **Reset PingOne User Password**, which sets a temporary password (visible in the run output) and forces a change at next sign-on. **Create PingOne User** provisions the account without credentials. Follow up with the recovery-code or password-reset workflow so the user can sign on. **Reset All PingID MFA Devices** removes every enrolled factor for the target user. They must re-enroll on next sign-in. Keep installer approval enabled unless your team explicitly wants open access. User-scoped workflows resolve PingOne users by email (falling back to username for environments that store the email there). Verify the target user's primary email in PingOne matches the address passed from Serval tickets or workflows. Group workflows take the exact group name and resolve the ID with a SCIM `name eq` filter. Group names are unique per environment only for environment-level groups — population groups can reuse a name across populations. When that happens the lookup refuses to guess; pass the optional **population name** input to scope it. Use **List PingOne Groups** to find the group spelling. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your PingID integration. # Presidio Source: https://docs.serval.com/sections/integrations/presidio Connect Serval to Presidio's Procurement API to look up dispatched assets, stock levels, and serial numbers on demand. ## About Presidio Presidio is an IT solutions and services provider. Serval connects to Presidio's Procurement API to read dispatched-asset records, stock levels, and serial numbers on your behalf whenever a Serval workflow runs. **Authentication:** An API **username** and **password** issued by Presidio, plus the exact **User-Agent** value Presidio assigned to your account. Serval exchanges the username and password for a short-lived JWT at Presidio's token endpoint and sends the JWT (as a bearer token) together with your User-Agent value on every request. The User-Agent is required because Presidio's gateway blocks any request — including authentication — that does not carry the expected value. **Regions:** Presidio publishes two regional API families from the same host: **EMEA** (`/api/v1/emea/...`, including stock and serial-number endpoints) and **APAC - Singapore** (`/api/v1/apac/singapore/...`, assets only). Your credentials determine which region you can read; workflows choose the region by endpoint path. **Data sync:** On-demand only - there is no background sync or scheduled ingestion. Serval reads from Presidio at the moment a Serval workflow runs. ## What the Presidio integration enables | Capability | Description | | - | - | | Look up dispatched assets | `GET /api/v1/emea/assets` (and `/api/v1/apac/singapore/assets`) return dispatched-asset records — order numbers, item details, serial numbers, tracking URLs, and delivery addresses — with filtered variants by date interval, item code, manufacturer, and free search terms. | | Read stock levels | `GET /api/v1/emea/stock` returns physical stock per item, optionally including serial numbers (EMEA only). | | Read serial numbers | `GET /api/v1/emea/serialnumbers` returns serial-number and asset-tag records by item (EMEA only). | | Call any Presidio API endpoint | A generic, typed API request action exposes every endpoint above with request/response types generated from Presidio's OpenAPI specification. | ## Get your credentials Presidio issues API credentials directly — there is no self-service developer portal. Ask your Presidio account contact for: The login pair for the Procurement API's token endpoint. Treat the password like any other credential. If it's ever exposed, ask Presidio to rotate it and update the Serval connection. The exact User-Agent string Presidio assigned to your account, e.g. `ProcurementAPI/1.0 (custom;yourcompany)`. Presidio's gateway rejects requests that do not send it, so it must be copied exactly. ## Connect in Serval All fields are required. An incomplete configuration is rejected with a message beginning "Invalid Presidio configuration". The API login Presidio issued for your account. The API password Presidio issued alongside the username. The exact User-Agent value from Presidio, copied character-for-character. After connecting, Serval runs healthchecks that authenticate and read a one-item sample from the assets API (trying EMEA first, then APAC - Singapore). The stock and serial-number checks apply to EMEA accounts only and are expected to fail for APAC - Singapore accounts. # Qualys Source: https://docs.serval.com/sections/integrations/qualys Connect Serval to the Qualys VM/PC API to read vulnerability data, manage scans, and work with reports and assets. ## About Qualys The Qualys integration lets Serval workflows work with your Qualys Vulnerability Management subscription through the VM/PC v2 API: per-host vulnerability detections, the vulnerability KnowledgeBase, VM scans, scan schedules, reports, asset groups, and asset IPs. Qualys's XML responses are converted to JSON automatically. **Authentication:** A Qualys username and password. Serval stores the credentials securely and sends them (HTTP Basic) only to the API server of the platform you select. **Access level:** You choose what Serval may do when you connect — and Serval enforces it server-side on every request: * **Read-only** — list and fetch data only. * **Scanner** — read, plus launch and manage scans and reports. * **Full** — read, scan, and manage assets (asset groups and asset IPs). **Data sync:** On demand. Serval reads data from Qualys when a workflow runs and does not perform a background sync. ## Create a Qualys API user Your Qualys subscription must include API access (most VMDR subscriptions do). Contact your Technical Account Manager if API calls return an access error. In Qualys, open **Users**, then create a user dedicated to Serval. A **Reader** role is sufficient for the Read-only access level; use a **Scanner** role if Serval should launch scans, or **Manager** for full asset management. Note your platform (shown under **Help > About** in the Qualys UI, e.g. US Platform 2) — you will select it in Serval. ## Connect in Serval Enter a recognizable instance name, such as Production. Choose the Qualys platform where your subscription is hosted. Serval only sends credentials to that platform's published API server. Enter the API user's username and password. Select Read-only, Scanner, or Full. Serval blocks any request beyond the selected level before credentials are attached, regardless of the Qualys user's own permissions. ## Verify the connection Serval checks that it can list host assets, VM scans, and reports, and read the vulnerability KnowledgeBase. A failed check normally means the credentials are invalid, the wrong platform was selected, or the Qualys user lacks the corresponding permission or module. Qualys enforces per-subscription API rate and concurrency limits and returns Retry-After headers when they are exceeded; Serval honors these automatically. Large detection queries should use the truncation\_limit parameter — Serval follows the pagination URL Qualys returns. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Qualys integration. # Ramp Source: https://docs.serval.com/sections/integrations/ramp Connect Ramp to Serval with OAuth so workflows can issue and manage corporate cards, invite and suspend users, and reach anything in Ramp's developer API. ## About Ramp Ramp is a corporate card and expense management platform for finance automation. Serval connects to Ramp over OAuth 2.0 and gives workflows typed access to Ramp's entire developer API, plus built-in workflows for inviting and suspending Ramp users and two installable workflow bundles for card and user management. After you connect, the connection is identified by your Ramp business's ID and legal name, which Serval reads from Ramp as the final step of the handshake. Serval only ever sends your Ramp credentials to one host for this integration: api.ramp.com. **Authentication:** OAuth 2.0 - either through Serval's own registered Ramp app (default: you approve on Ramp's consent screen, no setup on the Ramp side) or with your own Ramp developer app's Client ID and Client Secret (client credentials flow). **Data sync:** On-demand only. There is no background sync - Serval calls Ramp only when a workflow runs, attaching a current access token to every call. Connections made with Serval's app refresh their token automatically near expiry. Connections made with your own Ramp app exchange your app's Client ID and Client Secret for a fresh token on every request, and older connections that stored a Client ID and Client Secret directly work the same way - the difference is whose credentials are used, not how often they are exchanged. ## What the Ramp integration enables | Capability | Description | | - | - | | Generic Ramp API requests | Workflows can reach every endpoint in Ramp's developer API - users, cards, departments, limits, transactions, bills, accounting, and more - typed end-to-end against Ramp's API schema. Ramp returns large result sets in pages, and the bundled list workflows walk every page for you. | | User provisioning and deprovisioning | Built-in **Invite Ramp User** and **Suspend Ramp User** workflows send an email invite to a new user or look up an existing user by email and deactivate them. Five app access roles are supported: Admin, Employee, Bookkeeper, Guest, and IT Admin. | | Card Management workflow bundle | "Issue cards, manage spending limits, and control access to shared virtual cards in Ramp". Includes Issue New Ramp Card, Change Ramp Card Spend Limit, Get Ramp Card IDs and Limits For User, and Add Ramp User to Shared Virtual Card (each requiring installer approval by default), plus Search Ramp Spending Limits (no approval needed). | | User Management workflow bundle | "List, search, and manage users and department assignments in Ramp". Includes List All Ramp Users, List All Ramp Departments, Check User Email Exists in Ramp, and Search Ramp Departments (no approval needed), plus Update User Manager in Ramp and Update User Department in Ramp (installer approval by default). | | Scoped permissions | The connect dialog offers Ramp's full scope catalog - 54 scopes spanning accounting, bank accounts, bills, cards, departments, limits, reimbursements, transactions, users, vendors, and more (read and/or write variants). Two are locked as required and you choose the rest, so the connection can touch exactly what you allow. | Anything defined in the [Ramp API](https://docs.ramp.com/developer-api/v1/overview) can be accessed through Serval. ## Get your credentials Most teams need no Ramp-side setup at all: the default connection uses Serval's own registered Ramp app, so all you need is a Ramp admin who can click Approve on Ramp's consent screen. Creating your own Ramp developer app is only required if you want to bring your own credentials. Nothing to create. When you connect, Serval redirects you to Ramp's consent screen to authorize the scopes you selected, then completes the handshake automatically. Make sure the person connecting can authorize apps for your Ramp business. You'll create a Ramp developer API app and copy its Client ID and Client Secret. Ramp's official reference is the [Ramp Developer API overview](https://docs.ramp.com/developer-api/v1/overview). In Ramp, go to **Settings** > **Developer API** ([direct link](https://app.ramp.com/settings/business/developer-api)). You need Admin or Business Owner access. Click **Create New App**, name it (e.g. "Serval Integration"), accept the terms, and click **Create**. Under **Grant types**, enable **Client Credentials**. This is the flow Serval uses with your own app - no redirect or callback URL is needed. Under **Scopes**, enable every scope you plan to select in Serval. Ramp only grants the intersection of what the app allows and what is requested. Copy the **Client ID** (it starts with "ramp\_id\_") and the **Client Secret** (it starts with "ramp\_sec\_"). Don't forget to enable `business:read` on your Ramp app. Serval always reads your business information immediately after connecting, and the connection fails without it. ## Connect in Serval Add a new Ramp connection from your Serval integrations page. The dialog is titled **Connect Ramp**. The **Scopes** field is required (marked with an asterisk). `business:read` and `offline_access` are locked and can't be deselected - hovering them shows "Required for the integration to function". A fresh connection also pre-selects `users:read`, `users:write`, `transactions:read`, `cards:read`, and `departments:read`; remove optional scopes inline or add more through the **Edit scopes** modal. On a first-time connection, the Connect button stays disabled until at least one scope beyond the two locked ones is selected - hovering the disabled button shows "Please select at least one optional scope to connect". Reconnecting an existing Ramp connection (which opens with its current scopes loaded) is exempt, and any missing required scopes are merged back in automatically. Click Connect. You're redirected to Ramp's consent screen to approve the requested scopes, then returned to Serval, which finishes by reading your business's ID and legal name from Ramp. Open the three-dot menu next to Scopes and choose **Use your own Ramp app**. The form header reads "Using your own Ramp app" with the description "Authenticate with your Ramp app's client credentials"; the **Use Serval's app** link takes you back to the default flow. Enter your **Client ID** (placeholder "ramp\_id\_...") and **Client Secret** (placeholder "ramp\_sec\_..."). Both are required and whitespace is trimmed; submitting with either blank shows "Please provide both Client ID and Client Secret, or disable advanced mode." No Ramp consent screen appears for this path - that's expected. A successful connection is labeled with your Ramp business's legal name (or the business ID, if your business has no legal name on file). If your organization has disabled the Serval-managed OAuth option, the connect dialog shows the Client ID and Client Secret fields directly instead of behind the three-dot menu. ## Verifying the connection The Ramp connection ships with three built-in health checks: * **Read Ramp Business Information** - confirms the connection can read your business's name, ID, and active status. Success: "Successfully retrieved business information for: \[name]". Failure: "Unable to read business information from Ramp." * **List Ramp Users** - confirms the connection can list users and reports how many it found. Success: "Successfully listed \[number] users from Ramp". Failure: "Unable to list users from Ramp." * **List Ramp Cards** - confirms the connection can list cards and reports how many it found. Success: "Successfully listed \[number] cards from Ramp". Failure: "Unable to list cards from Ramp." Failure messages append a status-specific hint - see the gotchas below for the exact text. If the business information check passes but the users or cards check fails, your token is valid - the connection is just missing the matching scope (such as `users:read` or `cards:read`). Reconnect with those scopes selected, and if you brought your own Ramp app, make sure the same scopes are enabled on the app in Ramp. ## Gotchas and troubleshooting A first-time connection requires at least one scope beyond the locked `business:read` and `offline_access` pair - hover the button to see "Please select at least one optional scope to connect". Reconnecting an existing connection is exempt: it can keep a scope set containing only the required scopes, and required scopes are merged back in if missing. Immediately after getting a token, Serval reads your Ramp business's ID and legal name to finish the install - in both auth modes. With Serval's app, a failed read produces an error that lists the scopes Ramp actually granted and notes "This usually means the 'business:read' scope is missing." With your own Ramp app, Serval surfaces Ramp's raw error response from the business lookup instead. Either way, the usual fix is making sure `business:read` is granted - for a bring-your-own app, enable it on the app in Ramp's developer settings. Requested scopes are an ask, not a grant - Serval stores whatever Ramp actually granted in the token response. When using your own Ramp app, the scopes enabled on the app cap what can be granted: a scope selected in Serval must also be enabled on the Ramp side, or it silently won't be included. That's by design. Connections made with your own Ramp app always use the two-legged client credentials flow, so there's no redirect, no consent screen, and no callback URL to configure on your Ramp app. If the credential exchange fails, Serval surfaces Ramp's raw error response so you can see exactly what Ramp rejected. Failure messages append a hint based on the error Ramp returned: an authentication failure adds "The Ramp authentication token is invalid or expired. Please reconfigure the integration."; a permissions failure adds "The Ramp app may not have the required permissions. Check your OAuth scopes and permissions."; a not-found response adds "The requested resource was not found. This may indicate missing permissions or incorrect configuration."; and a Ramp server error adds "Ramp returned a server error. This is likely a temporary issue with Ramp's API - please try again later." The connect dialog pre-selects the required pair plus `users:read`, `users:write`, `transactions:read`, `cards:read`, and `departments:read`. A connection created without any scopes supplied (including legacy installs with no stored scopes) instead defaults to `business:read`, `users:read`, `users:write`, and `offline_access`. If a connection can do less than you expect, check which scopes it actually holds and reconnect with more. Ramp connections created before the current connect flow stored the Client ID and Client Secret as custom integration data. They are still supported - every time a workflow runs, Serval exchanges those stored credentials for a fresh access token. No migration is needed. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Ramp integration. # Rancher Source: https://docs.serval.com/sections/integrations/rancher Connect Serval to your self-hosted Rancher management server so workflows can list and manage Rancher users, global roles and role bindings, role templates, and projects. ## About Rancher Rancher is a management platform for Kubernetes clusters. This integration connects Serval to your self-hosted Rancher management server so workflows can read and manage Rancher users, global roles and role bindings, role templates, and projects. The integration is currently marked **Beta** in the connect screen, so its capabilities and prebuilt workflows may still change. **Authentication:** API key (a Rancher Bearer Token, plus the domain of your Rancher instance). There is no OAuth flow - the token stays valid until it expires or you replace it in Rancher. **Data sync:** None - everything is on demand. Serval only calls your Rancher server when you save the connection or a workflow runs. There is no background sync, no webhooks, and no data ingestion. ## What the Rancher integration enables | Capability | Description | | - | - | | Rancher API request | A generic workflow action that can call any of the 31 supported endpoints on Rancher's management APIs, covering users, global roles, global role bindings, role templates, projects, cluster and project role bindings, tokens, kubeconfigs, and audit policies. | | List Rancher Users | Prebuilt workflow that lists all users in your Rancher management plane. Installs with no approval required by default. | | List Global Roles | Prebuilt workflow that lists all global roles defined in Rancher. Installs with no approval required by default. | | List Global Role Bindings | Prebuilt workflow that lists all global role bindings, showing which users hold which roles. Installs with no approval required by default. | | List Projects | Prebuilt workflow that lists all projects across namespaces. Installs with no approval required by default. | | List Role Templates | Prebuilt workflow that lists the role templates used for cluster and project access control. Installs with no approval required by default. | | Create Global Role Binding | Prebuilt workflow that assigns a global role (such as admin or user) to a Rancher user. Installs with installer approval required by default. | | Delete Global Role Binding | Prebuilt workflow that removes a user's global role binding. Installs with installer approval required by default. | These are Rancher's standard management APIs - see Rancher's [API quickstart](https://ranchermanager.docs.rancher.com/api/quickstart) for background on the underlying interfaces. ## Get your credentials Serval needs two things: the domain of your Rancher instance and a Rancher API key's **Bearer Token**. Create the key as a user with admin-level global permissions, following Rancher's [API key guide](https://ranchermanager.docs.rancher.com/reference-guides/user-settings/api-keys). Sign in to the Rancher UI as an administrator, click your user avatar in the upper right, and choose **Account & API Keys**. Click **Create API Key**. Optionally add a description and set an expiration. Do not select a cluster scope. Serval talks to Rancher's management plane, and a cluster-scoped key only works against a single cluster, so it will fail Serval's connection test. Click **Create**, then copy the **Bearer Token** value right away - it is shown only once. The **Endpoint** shown on the same screen contains your instance domain: use just the domain part, without the "https\://" prefix. Copy the full **Bearer Token** string, not the separate access key or secret key shown alongside it. If you lose it, delete the key and create a new one. Rancher API keys can expire (your server's token settings cap the maximum lifetime). When the key expires, the Serval connection stops working until you paste in a new token, so note the expiration date you choose. ## Connect in Serval In Serval, go to the integrations page and select **Rancher** (marked Beta). Enter the bare domain of your Rancher instance, for example "rancher.example.com" - no "https\://" prefix and no path. Serval always connects over HTTPS. Paste the full Bearer Token you copied from Rancher into the **Bearer Token** field. This is a password-style field; after saving, Serval shows it masked, with only the last 4 characters visible. When you save, Serval tests the credentials by listing the users in your Rancher management plane and rejects the save if that call fails. Neither field shows inline validation messages, and the underlying failure reason is not surfaced - a failed save shows a general error such as "Failed to connect service" or "Failed to install integration". See the troubleshooting section below for what to check. When editing an existing connection, the **Instance Domain** comes pre-filled and the **Bearer Token** appears masked with a **Replace** option. Leave the token untouched (or blank) to keep the stored token - only enter a value when rotating the key. Leaving **Instance Domain** blank likewise keeps the stored domain. Serval re-tests the connection only when a new token is submitted, so saving a domain change without a new token does not re-test the connection. ## Verifying the connection Serval tests the Rancher connection at save time only: when you first connect, and again whenever you submit a new Bearer Token, it lists the users in your Rancher management plane and rejects the save if that call fails. There are no recurring health checks for this integration, so nothing runs in the background after you connect. To verify the connection at any time, run the **List Rancher Users** prebuilt workflow - if it returns your users, the connection works. If the list workflows succeed but the **Create Global Role Binding** or **Delete Global Role Binding** workflows fail, the token's user can read users but lacks permission to change global role bindings. Recreate the API key under a full admin account. ## Gotchas and troubleshooting Serval does not surface the underlying reason for a failed connection test - you only see a general error such as "Failed to connect service" or "Failed to install integration". Before retrying, check the three usual causes in order: the **Instance Domain** is filled in, spelled correctly, and reachable over HTTPS; the API key was created with **No Scope**; and the **Bearer Token** was pasted in full. Failed edits show messages like "Failed to update configuration" or "Failed to update integration" instead. Serval calls Rancher's management plane, not an individual cluster. A key scoped to a single cluster only authorizes that cluster's Kubernetes API, so the connection test fails even though the key itself is valid. Rancher's own API quickstart likewise instructs creating the key with no scope. The connection test lists users in the Rancher management plane. If the key belongs to a user without global permission to list users, the connection is rejected. Use a key created by an admin-level account. The **Instance Domain** field takes the domain only (for example "rancher.example.com"). Serval adds the "https\://" prefix itself, so pasting a full URL produces a broken address, and Rancher installs served over plain HTTP are not supported. Rancher API keys expire based on your server's token lifetime settings, and Serval has no automatic refresh for them. Because this integration has no recurring health checks, an expired key surfaces as workflow runs failing - they keep failing until you open the integration settings and replace the Bearer Token. Serval only re-validates the connection when a new Bearer Token is submitted. If you change just the **Instance Domain**, the update saves without a test call, so a typo is not caught until the next workflow run fails. The **Create Global Role Binding** and **Delete Global Role Binding** workflows install with installer approval required, while the five list workflows install with no approval. Adjust the approval procedure after installing if your team needs different controls. The Rancher connect tile is marked Beta, so the available actions and prebuilt workflows may still change. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Rancher integration. # Rapid7 Source: https://docs.serval.com/sections/integrations/rapid7 Connect Serval to the Rapid7 Insight platform so workflows can call InsightIDR, InsightAppSec, InsightConnect, and the Insight Account API on demand with a single platform API key. ## About Rapid7 Rapid7 is a security operations platform built around the Insight cloud, spanning detection and response (InsightIDR), application security (InsightAppSec), log management (InsightOps), and orchestration (InsightConnect). Serval connects to your regional Insight platform with a single API key, and that one connection fans out across the Insight product APIs plus the platform Account API. Everything happens on demand from workflows - there is nothing to install on the Rapid7 side. **Authentication:** API key (Insight platform key) - you provide your regional API Domain and an Insight platform API key, and Serval attaches the key to every request it makes on your behalf. Serval only ever sends the key to your regional Insight API host. **Data sync:** On-demand only. There is no background sync and no entity ingestion - Serval reads and writes Rapid7 data only when a workflow runs. ## What the Rapid7 integration enables | Capability | Description | | - | - | | InsightIDR requests | Query and update detection and response data such as investigations and alerts. | | InsightAppSec requests | Work with application security data: apps, scans, scan configs, and vulnerabilities. | | InsightConnect requests | Call the orchestration and automation API. | | Insight Account requests | Manage platform-level resources such as your organization, users, and API keys. | | InsightOps requests | Call the log management API. Not currently functional through Serval - see Gotchas before relying on this. | | AI endpoint discovery | When authoring workflows, Serval AI can discover the available endpoints for InsightAppSec, InsightOps, InsightConnect, and the Insight Account API. InsightIDR endpoints are not registered, so for InsightIDR the AI works from Rapid7's public API documentation instead. | Anything the [Rapid7 Insight platform APIs](https://docs.rapid7.com/insight/api-overview/) serve from your regional Insight API host can be accessed through Serval. ## Get your credentials You need a Rapid7 Insight platform API key - either a **User API key** or an **Organization API key**. The same key works across all Rapid7 Insight products in your region, but it inherits the product access of its owner, so the owner must have access to each Insight product you plan to use. Rapid7's official guide is [Managing platform API keys](https://docs.rapid7.com/insight/managing-platform-api-keys/). Sign in at [insight.rapid7.com](https://insight.rapid7.com/). Click the gear icon in the top right corner, then click **API keys** in the dropdown menu. Select either **User API keys** or **Organization API keys**. Click **Generate new key** and give it a descriptive name. Copy and save the API key right away - you will not be able to view it again. Your region determines your API domain. Common regions are us, us2, eu, ca, au, and ap - for example, the us region uses us.api.insight.rapid7.com. Rapid7 shows the API key only once, at creation time. If you lose it, you will need to generate a new key. Before generating the key, confirm its owner (the user, or the organization) has access to every Insight product you intend to call from Serval. The key carries exactly that owner's product access. ## Connect in Serval In Serval, add a new Rapid7 connection. Enter only the bare regional host in lowercase, for example us.api.insight.rapid7.com - no https prefix, no path, no trailing slash. The form shows the helper text "Your Rapid7 API domain. Common regions: us, us2, eu, ca, au, ap. Example: us.api.insight.rapid7.com". Anything else is rejected with "Must be a valid Rapid7 API domain (e.g., us.api.insight.rapid7.com, us2.api.insight.rapid7.com)", and leaving it empty shows "This field is required". The region prefix (for example "us") becomes the connection's name. Paste the Insight platform API key you copied from Rapid7 into the **API Key** password field ("Your Rapid7 API key"). Click **Submit**. If installation fails, the form shows "Failed to install integration" with details appended when available. Serval stores both values and attaches the key to every Rapid7 request your workflows make. When you open the connection's settings later, the API Domain is shown in full, and the API key appears masked - bullet characters plus its last 4 characters. Saving an update with the API Key untouched or blank keeps the existing key, and the same applies to the API Domain, which is pre-filled with the current value - enter a value only for what you want to change. To rotate the key, click **Replace** (or the pencil icon, depending on the form) next to the masked value and paste the complete new key into the "Enter new value" box. Changing the API Domain also renames the connection, since the connection name follows the domain's region prefix. ## Verifying the connection Serval does not test your credentials when you save them - a mistyped key, a revoked key, or a domain from the wrong region is accepted at save time - and this integration does not ship any built-in connection health checks. The first signal of a problem is a failed request when a workflow runs. To verify a new connection, run a workflow that makes a small read-only call - for example, an Insight Account request that lists your platform API keys. * A successful call proves the API Domain is reachable and the Insight platform accepts the key. * An authentication failure usually means the key is invalid or revoked, or the API Domain does not match the region where the key was created. Re-check the region prefix and, if needed, generate a fresh key in Rapid7 and update the connection. A successful platform call proves the key is valid on the Insight platform - it does not prove the key's owner has access to every Insight product. If platform calls succeed but one specific product returns permission errors, grant the key's owner access to that product in Rapid7, or connect with a different key. ## Gotchas and troubleshooting The connect form accepts only a bare regional Insight host in lowercase. Values with an https prefix, a path after the host, a trailing slash, or stray spaces fail with "Must be a valid Rapid7 API domain (e.g., us.api.insight.rapid7.com, us2.api.insight.rapid7.com)". Enter only the host, for example us.api.insight.rapid7.com. A single platform key covers all Rapid7 products in your region, but it carries only the product access of the user or organization that owns it. If InsightAppSec calls succeed while InsightIDR returns a 403 (or vice versa), grant the key's owner access to that product in Rapid7, or use a different key. InsightOps lives on a separate log-management host - your region prefix followed by rest.logs.insight.rapid7.com - which is outside the hosts this integration is allowed to call. Serval only permits requests to your regional Insight API host, so InsightOps calls are rejected with "request URL is not allowed for service rapid7". Treat InsightOps as not currently functional through this integration, even though its endpoints appear in the AI endpoint catalog. InsightIDR, InsightAppSec, and Insight Account requests automatically add their product's API prefix, so pass only the endpoint as shown after that prefix in Rapid7's documentation - including the prefix again produces a doubled address and not-found errors. InsightConnect is the exception: its endpoints already include the product prefix, exactly as they appear in the endpoint catalog. Unlike the other products, InsightIDR calls are freeform - Serval cannot validate the endpoint or method before the request runs, and Serval AI has no registered endpoint catalog for InsightIDR. Double-check InsightIDR endpoints against Rapid7's InsightIDR API documentation if calls return not-found errors. The region prefix of your API Domain (for example "us") is used as the connection's name and to derive the InsightOps log-management host. If your Rapid7 data lives in a different region, update the API Domain on the connection rather than working around it. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Rapid7 integration. # Recorded Future Source: https://docs.serval.com/sections/integrations/recorded-future Connect Serval to Recorded Future so workflows can enrich indicators, triage alerts, manage watchlists, and check identity exposures with a single API token. ## About Recorded Future Recorded Future is a threat-intelligence platform that scores and contextualizes indicators of compromise, publishes alerts and analyst research, and tracks exposed credentials. Serval connects to the Recorded Future API at api.recordedfuture.com with a single API token, and that one connection covers the enrichment, alerting, list, analyst-note, identity, and SOAR APIs. Everything happens on demand from workflows - there is nothing to install on the Recorded Future side. **Authentication:** API token - you provide a Recorded Future API token, and Serval sends it in the X-RFToken header on every request it makes on your behalf. Serval only ever sends the token to api.recordedfuture.com. Adjacent Recorded Future products with separate tokens, such as the Sandbox and Attack Surface Intelligence, aren't part of this integration. **Data sync:** On-demand only. There is no background sync and no entity ingestion - Serval reads and writes Recorded Future data only when a workflow runs. ## What the Recorded Future integration enables | Capability | Description | | - | - | | Indicator enrichment | Look up risk scores, triggered risk rules, and evidence for IPs, domains, URLs, file hashes, and CVEs. | | Bulk enrichment and triage | Enrich up to 1,000 indicators in one SOAR API call, or get a one-call risky-or-not verdict against a triage context such as phishing or C2. | | Alert triage | Search classic alerts, fetch the hits that triggered them, and update status, assignee, and notes. | | Playbook alerts | Search playbook alerts across categories such as domain abuse and novel identity exposures, read category details, and update status, priority, and assignee. | | Watchlist management | Create custom lists and add or remove the entities Recorded Future should monitor. | | Identity exposure checks | Search leaked credentials for your watched domains, look up specific users, and check whether passwords appear in breach data. | | Analyst notes | Search and read Insikt Group and enterprise analyst notes, or publish your own. | | Detection rules | Search Sigma, YARA, Snort, Nuclei, and Suricata rules linked to threats you care about. | | Entity resolution | Resolve free-text names such as a malware family or vendor to Recorded Future entity IDs. | | AI endpoint discovery | When authoring workflows, Serval AI can discover the curated Recorded Future endpoints and their parameters. | The integration covers a curated subset of the [Recorded Future APIs](https://api.recordedfuture.com/index.html) - Connect enrichment and search, Alert, Playbook Alert, List, Analyst Note, Entity Match, Detection Rule, Identity, and SOAR. ## Get your credentials You need a Recorded Future API token. Tokens are generated in the Recorded Future portal by an Enterprise Administrator, and each token carries the API entitlements of your licensed modules - the same token works across all the APIs your subscription covers. Recorded Future's guide is [Requesting API Tokens](https://support.recordedfuture.com/hc/en-us/articles/4411077373587-Requesting-API-Tokens) (customer login required). Sign in at [app.recordedfuture.com](https://app.recordedfuture.com/) with an Enterprise Administrator account. Open the menu in the upper right corner, select **User Settings**, then select **API Access**. Select **Generate New API Token**, give it a descriptive name such as Serval, and choose the API services it should cover. Copy and save the token right away. Only Enterprise Administrators can generate API tokens. If you aren't an administrator, ask one to generate the token for you, or submit an integration support ticket to Recorded Future specifying which API offering you need. Endpoint access is baked into the token from your licensed modules - for example, vulnerability enrichment needs the Vulnerability Intelligence module and identity lookups need Identity Intelligence. If your organization adds a module later, regenerate the token to pick up the new entitlements. ## Connect in Serval In Serval, add a new Recorded Future connection. Paste the token into the **API Token** password field ("Recorded Future API token, generated by an Enterprise Administrator in the Recorded Future portal under User Settings -> API Access."). Leaving it empty shows "This field is required". Click **Submit**. If installation fails, the form shows "Failed to install integration" with details appended when available. Serval stores the token securely and attaches it to every Recorded Future request your workflows make. When you open the connection's settings later, the token appears masked - bullet characters plus its last 4 characters. To rotate it, replace the masked value with the complete new token and save. ## Verifying the connection The integration ships five built-in health checks: 1. **Test Recorded Future Connection** - searches your custom lists, which every module is entitled to. Success reports "Successfully connected to the Recorded Future API". Failure reports "Unable to connect to Recorded Future. Verify the API token is valid and hasn't expired or been revoked." 2. **Check Enrichment API Access** - lists IP risk rules, a static metadata call with no enrichment-quota cost. Failure normally means the token's modules don't include SecOps, Threat, or Brand Intelligence. 3. **Check Alert API Access** - fetches a single alert rule. Alerts are available on every module except SecOps Intelligence. 4. **Check Playbook Alert API Access** - fetches the playbook alert category and status enumerations. 5. **Check SOAR Bulk-Enrichment Access** - lists the static triage contexts. Failure normally means the token's modules don't include SecOps or Threat Intelligence. Only the first check indicates a broken connection outright. If it passes while a later check fails, the token is valid but its modules don't cover that API - the failure message names the modules that unlock it. ## Gotchas and troubleshooting Every Recorded Future API is gated by module entitlements that are baked into the token at generation time. A 403 with "Missing API privileges" means the token's modules don't cover that endpoint - it isn't an authentication failure. If your organization licensed a new module after the token was created, regenerate the token in the Recorded Future portal. A 401 means the token itself is invalid - expired, revoked, or mistyped. Generate a fresh token in the Recorded Future portal and update the connection. Standard Recorded Future API subscriptions include 5,000 API calls per day across all the APIs, and bursts of traffic can return HTTP 429. For enriching many indicators, prefer one SOAR bulk-enrichment call (up to 1,000 indicators) over a loop of per-indicator lookups - it's one call toward the quota and returns risk scores for the whole batch. The URL enrichment endpoint takes the full URL as a path parameter. Serval URL-encodes path parameters automatically, so pass the raw URL as the id - encoding it yourself produces a double-encoded lookup that misses. The enrichment search endpoints and classic alert search cap limit plus from at 1,000 - deeper pages aren't reachable. Playbook alert, analyst note, and identity searches use cursor offsets instead and aren't capped this way. Recorded Future Sandbox (sandbox.recordedfuture.com) and Attack Surface Intelligence (served from api.securitytrails.com) use different hosts and different tokens. This integration only calls api.recordedfuture.com, so those products are out of scope. Endpoints that return raw files - alert screenshot images, analyst-note attachments, and bulk risk-list downloads - are excluded from the endpoint catalog because Serval's request pipeline is JSON-based. Risk data is available through the enrichment and SOAR endpoints instead. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Recorded Future integration. # Revivn Source: https://docs.serval.com/sections/integrations/revivn Connect Revivn to Serval with OAuth client credentials so workflows can list assets, mail-back retrievals, and pickups through the Revivn API. ## About Revivn Revivn is an IT asset disposition platform for recovering, tracking, and repurposing hardware. Serval connects with OAuth 2.0 client credentials (Client ID and Client Secret). Serval exchanges them for short-lived access tokens at `https://api.revivn.dev/oauth/token` and refreshes tokens automatically. All API traffic goes to `api.revivn.dev`. **Authentication:** OAuth 2.0 client credentials. Revivn does not use a static API key for the REST API. **Data sync:** On-demand only. Serval calls Revivn when a workflow runs. This integration is in beta. ## What the Revivn integration enables | Capability | Description | | - | - | | Assets | List and inspect received assets, including serial numbers and certificate-of-destruction links. | | Asset retrievals | List and create mail-back laptop retrievals (the flow Datadog uses to track employee return shipments). | | Pickups | List and create pickup requests. | | Workflow authoring | Serval AI can discover Revivn v1 endpoints when building workflows. | Anything in the [Revivn API documentation](https://api-docs.revivn.com/) can be reached through Serval. ## Get your credentials Create an OAuth application in the Revivn app and copy the Client ID and Client Secret. Log in to the [Revivn app](https://revivn.app), then go to **API** → **API Credentials**. Click **Create Application**, enter a name (for example "Serval"), and save. Copy both values immediately. You may not be able to view the secret again after you leave the page. Store the Client Secret securely when it is shown. If you lose it, create a new application in Revivn and update Serval. ## Connect in Serval Add a new Revivn connection from Serval's integrations page. **Instance Name** is a label for this connection in Serval (for example "Production Revivn"). Paste the **Client ID** and **Client Secret** from Revivn. Do not use API key mode for a custom application — Revivn expects OAuth bearer tokens. Submit the form. Serval runs health checks automatically after a successful connect. ## Verifying the connection Serval ships four health checks: * **Test Connection** — lists one page of assets. Success: "Successfully connected to the Revivn API." Failure: "Unable to connect to Revivn. Verify your Client ID and Client Secret from Revivn App → API → API Credentials." * **List Assets** — confirms read access to `/api/v1/assets`. * **List Pickups** — confirms read access to `/api/v1/pickups`. * **List Asset Retrievals** — confirms read access to `/api/v1/asset_retrievals`. ## Gotchas and troubleshooting Re-enter valid Client ID and Client Secret on the Revivn connection in Serval. If the connection was set up as a custom application with an API key instead of OAuth, switch to the catalog **Revivn** integration and connect with OAuth credentials. Datadog and other early adopters sometimes used a **custom application** with the wrong auth type (`X-Api-Key`). The catalog Revivn integration uses OAuth client credentials and automatic token refresh. Prefer the catalog integration for new setups. # RightCrowd Source: https://docs.serval.com/sections/integrations/rightcrowd Connect Serval to your gateway-fronted, self-hosted RightCrowd server so workflows can manage cardholders, access cards, and physical access on demand. ## About RightCrowd [RightCrowd](https://www.rightcrowd.com/) is a physical identity and access management (PIAM) platform covering workforce access, visitor management, and the cardholder and credential lifecycle. The Serval RightCrowd integration connects to your self-hosted RightCrowd server through its SOAP web services. It is built for deployments where the RightCrowd server sits behind an API gateway, such as Azure API Management secured by Microsoft Entra ID. Once connected, Serval workflows can look up, create, update, suspend, and resume cardholders directly on your RightCrowd server. **Authentication:** OAuth2 client credentials against the identity provider that secures your API gateway (for example Microsoft Entra ID). Serval stores your Client ID, Client Secret, Token URL, and optional Scopes, exchanges them for an access token at your token endpoint, and attaches it to every outbound call automatically. Direct basic-auth connections to a RightCrowd server are not supported yet. **Data sync:** On-demand only. There is no scheduled sync, directory import, or resource ingestion - data moves only when a workflow runs a RightCrowd SOAP operation. ## What the RightCrowd integration enables | Capability | Description | | - | - | | SOAP requests from workflows | The "RightCrowd ProvisioningService1 SOAP API request" action runs any supported SOAP operation by name and returns the parsed response, plus the raw request and response XML for debugging. | | Cardholder lifecycle management | AddCardholder, ModifyCardholder, DeleteCardholder, SuspendCardholder, ResumeCardholder, and ForgetCardholder manage cardholder records, access methods (cards), access levels, and activation dates on your RightCrowd server. | | Cardholder lookup and search | GetCardholder, LoadCardholder, and SearchCardholders retrieve cardholder records, including custom data fields (CDFs), access levels, biometrics, and attachments. | | Entity categorization | CategoriseEntity assigns RightCrowd entities to categories. | | Automatic authentication and routing | Serval fetches OAuth2 bearer tokens for you and routes every call to your server's ProvisioningService1 endpoint - no token handling in workflows. | The supported operations are the ten listed above, fixed by the ProvisioningService1 service definition that ships with Serval. ## Get your credentials RightCrowd's SOAP web services have no public API documentation, and the gateway in front of your server (and its OAuth setup) is owned by your organization. Coordinate with whoever operates the gateway. For the typical setup - Azure API Management secured by Microsoft Entra ID - you create an app registration that Serval uses as its OAuth2 client. See Microsoft's guide to the [OAuth 2.0 client credentials flow](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow). In the Azure portal, search for and select **App registrations**, then select **New registration** and register a client application for Serval. On the app's **Overview** page, record the **Application (client) ID**. This is the **Client ID** field in Serval. Under **Manage**, select **Certificates and secrets**, create a **New client secret**, and copy its value immediately. This is the **Client Secret** field. The secret value is only shown once at creation. If you lose it, create a new secret. Build the token endpoint from your tenant: "[https://login.microsoftonline.com/tenant-id/oauth2/v2.0/token](https://login.microsoftonline.com/tenant-id/oauth2/v2.0/token)", replacing "tenant-id" with your tenant's ID. For **Scopes**, use the application ID URI of the gateway's backend app suffixed with "/.default" (for example "api://backend-app-client-id/.default"), and have an admin grant the client app the required application permission on that backend app. Ask your gateway owner for the base URL that fronts the RightCrowd web services. You will enter only the host and base path in Serval - Serval appends "/RightCrowd/WS/ProvisioningService1.asmx" itself. For gateway-side token validation setup, see [Protect an API in Azure API Management with OAuth 2.0 and Microsoft Entra ID](https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-protect-backend-with-aad). Direct connections to a RightCrowd server using basic authentication are not supported yet. The integration requires an OAuth2-capable gateway in front of the server. ## Connect in Serval Find RightCrowd in the Serval integrations catalog and start a new connection. Every field except Scopes is required and marked with an asterisk. Enter only the host and base path, for example "[https://api.example.com/](https://api.example.com/)". The form describes the field as "Base URL for the RightCrowd API (do not include /RightCrowd/WS/ - just the host and base path)". Leaving it blank shows "This field is required". Do not include "/RightCrowd/WS/" - Serval appends the web services path automatically. The URL must start with "https\://" or "http\://", or saving fails with an error that includes "API base URL must start with https\:// or http\://". Paste the Application (client) ID from your app registration. The form describes it as "OAuth2 Client ID for API access". Leaving it blank shows "This field is required". Paste the full client secret value into the masked password input. The form does not flag a blank secret inline - if you leave it empty, saving fails with an error that includes "Invalid RightCrowd configuration: client secret is required". Paste your OAuth2 token endpoint, for example "[https://login.microsoftonline.com/tenant-id/oauth2/v2.0/token](https://login.microsoftonline.com/tenant-id/oauth2/v2.0/token)". Leaving it blank shows "This field is required", and it must start with "https\://" or "http\://", or saving fails with an error that includes "token URL must start with https\:// or http\://". Add each OAuth scope as a tag, for example "api://client-id/.default". You can paste a comma-separated list and the form will split it. Adding a scope that is already in the list shows a message ending in "is already added". For Entra ID gateways, the ".default" application scope of the gateway's backend app is typically required to get a token the gateway will accept. Save the form. Serval validates only the field formats at save time. If a value is rejected, the error starts with "Failed to install integration" and names the problem, for example "Invalid RightCrowd configuration: API base URL must start with https\:// or http\://". When editing this connection later, the Client Secret appears masked with a control to replace it (a pencil icon on the connection settings form, or a Replace button in the configure dialog). Re-enter the complete secret every time you save changes - even if you are only changing another field. Saving without re-entering it is rejected: depending on where you edit, you see a generic "Failed to update configuration" message or an error that includes "client secret is required". Keep the secret somewhere retrievable, or be ready to create a new one in your identity provider whenever you edit the connection. ## Verifying the connection Saving the connection checks field formats only. Serval does not request a token from your Token URL or call your gateway at save time, and this integration does not ship a built-in connection health check - the first end-to-end proof comes from the first SOAP call. To verify the connection, run a workflow that uses the "RightCrowd ProvisioningService1 SOAP API request" action - a GetCardholder call makes a good smoke test. A successful response confirms the whole chain end to end: gateway routing, OAuth2 token issuance from your Token URL, and SOAP connectivity to the RightCrowd web services. If the first SOAP call fails right after connecting, check **Scopes** first. A token request can succeed with the wrong scope, but an Entra ID-secured gateway typically only accepts tokens that carry its backend app's ".default" application scope. Confirm the scope and the admin-granted application permission with your gateway owner. ## Gotchas and troubleshooting The most common cause is including "/RightCrowd/WS/" in the **API Base URL**. Serval appends "/RightCrowd/WS/ProvisioningService1.asmx" automatically, so entering the full web services path yourself doubles the segment and every call fails. Enter only the host and base path, for example "[https://api.example.com/](https://api.example.com/)". The connection form requires the full Client Secret on every save, not just the first one. Use the pencil icon (settings form) or Replace button (configure dialog) on the **Client Secret** field, paste the complete secret value, then save again. Plan for this: keep the secret somewhere retrievable, or be ready to mint a new one, whenever you change any other setting on the connection. This integration is built for gateway-fronted deployments (for example Azure API Management with Microsoft Entra ID). The gateway typically only accepts tokens that carry its backend app's ".default" application scope and an admin-granted application permission. Direct connections to a RightCrowd server using basic authentication are not supported yet. There is no generic REST request action for RightCrowd. Workflows must use the "RightCrowd ProvisioningService1 SOAP API request" action, and operation names must match the service definition's casing exactly (GetCardholder works, getCardholder does not). Available operations: AddCardholder, ModifyCardholder, DeleteCardholder, SuspendCardholder, ResumeCardholder, ForgetCardholder, GetCardholder, LoadCardholder, SearchCardholders, and CategoriseEntity. The connection's identity in Serval is derived from the host and path of the **API Base URL**. Pointing an existing connection at a different base URL re-keys it as a different connection instance, so treat a base URL change like setting up a new connection. Both the API Base URL and Token URL accept "https\://" or "http\://". Use "https\://" in production - your credentials and tokens transit these URLs. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your RightCrowd integration. # Rippling Source: https://docs.serval.com/sections/integrations/rippling Connect Rippling to Serval to sync your workforce and supergroups, manage supergroup membership, and call the Rippling API from custom workflows. ## About Rippling Rippling is a workforce management platform that combines HR, IT, payroll, and finance in one place. Serval connects to Rippling with an API key and automatically imports your Rippling workers as Serval users and your supergroups as group resources. Serval can also grant and revoke supergroup membership through access management, and your custom workflows can reach the full Rippling API through a typed request action. **Authentication:** Rippling API key (v2), stored encrypted and sent by Serval as a bearer token on every request it makes to Rippling on your behalf. **Data sync:** Two background full syncs run every 4 hours - one for users (workers) and one for groups (supergroups). Membership changes you make through Serval's access management are applied on demand. ## What the Rippling integration enables | Capability | Description | | - | - | | User sync (HRIS) | Imports Rippling workers as Serval users every 4 hours, capturing work email, preferred or given names, and active status. | | Group sync (supergroups) | Imports Rippling supergroups of type ALIAS as Serval group resources every 4 hours, each with a single "member" entitlement and the members on its inclusion list. Supergroups also feed Serval's org-group information. | | Access management provisioning | Grants and revokes supergroup membership for Serval users, matched to Rippling workers by exact work email. | | Health checks | Four built-in checks verify that Serval can authenticate and has the read access the syncs depend on. | | Custom workflow API access | A typed Rippling API request action exposes more than 30 Rippling REST endpoints - companies, departments, teams, workers, users, supergroups, custom objects and their records, and more - to your custom workflows. | The integration ships no pre-packaged workflow templates: user sync, group sync, and provisioning are built-in platform capabilities, and everything else is available through custom workflows. Anything defined in the [Rippling API](https://developer.rippling.com/) can be accessed through Serval. ## Get your credentials Serval needs a Rippling API key for the **v2 REST API** with **API Tier 1** access. The scopes you grant determine what Serval can do: | Scope | Needed for | | - | - | | sso-me.read | The connection health check | | workers.read | User sync and worker lookup during provisioning | | users.read | The "List Rippling Users" health check | | supergroups.read | Group sync and membership sync | | supergroups.read-write | Access management provisioning - only if you want Serval to add and remove supergroup members | Additional read scopes (companies.read, departments.read, teams.read, custom-fields.read, and so on) are only needed if your custom workflows call those parts of the API. See the [Rippling developer documentation](https://developer.rippling.com/) for details. You need admin access to create API keys. This is where Rippling manages API keys for the v2 REST API. Create a new API key and give it a recognizable name, for example "Serval Integration". Choose the scopes from the table above that match how you plan to use the integration. The generated API key is only shown once - copy it before closing the page. The key must be for Rippling's v2 REST API. Keys for Rippling's legacy platform API will not work with this integration. ## Connect in Serval In Serval, add the **Rippling** integration to open its connect form. A free-text field that becomes the display name of this connection in Serval. A password-type field for the Rippling API key you created above. If installation fails, you will see "Failed to install integration" with details from the backend appended, or the general message "Failed to save configuration. Please try again." Neither field is marked required and there is no validation on the form - it will submit with blanks. A blank submission creates a connection that simply fails every health check, so always fill in both fields. **Editing the connection later:** when you reopen the configuration, the API key appears masked (bullets plus the last 4 characters). Leaving it untouched keeps your stored key, and so does choosing to replace it but leaving the field blank - to rotate, paste the complete new key. Leaving Company Name blank keeps the existing name; entering a new value renames the connection. If an update fails, the integration settings page shows "Failed to update configuration", while the configure dialog shows "Failed to update integration:" followed by error details. ## Verifying the connection After connecting, four health checks confirm the integration is working: * **Test Rippling Connection** - verifies Serval can authenticate and reach Rippling, reporting the connected account. Success: "Successfully connected to Rippling as \[email]." Failure: "Unable to reach Rippling." followed by a shared error explanation (see the troubleshooting section below). * **List Rippling Workers** - verifies the read access to employee data that user sync depends on. Success: "Successfully retrieved workers list from Rippling (found \[number] worker(s) in sample)." Failure: "Unable to list workers from Rippling." plus the shared suffix. * **List Rippling Supergroups** - verifies the read access to ALIAS supergroups that group sync depends on. Success: "Successfully retrieved supergroups list from Rippling (found \[number] supergroup(s) in sample)." Failure: "Unable to list supergroups from Rippling." plus the shared suffix. * **List Rippling Users** - verifies read access to user account data. Success: "Successfully retrieved users list from Rippling (found \[number] user(s) in sample)." Failure: "Unable to list users from Rippling." plus the shared suffix. If "Test Rippling Connection" is green but the worker, supergroup, or user checks fail, your key authenticates but is missing read scopes - the connection check only needs the identity scope. Note also that all four checks can pass while provisioning still fails, because none of them test the write scope (supergroups.read-write) that adding and removing supergroup members requires. ## Gotchas and troubleshooting All four health checks share the same error wording. On a 401 you will see "The OAuth token may have expired or been revoked. Please reconnect your Rippling integration." - in practice this means your API key is invalid or has been revoked; re-open the configuration and paste a new key. Other shared messages: 403 - "This may be due to missing API scopes. Please check that your Rippling application has the required permissions (API Tier 1)."; 404 - "The requested resource was not found. This may indicate a configuration issue."; 429 - "Rippling rate limit reached. Please try again in a few moments."; 500 - "Rippling API is experiencing issues. Please try again later."; anything else - "Error:" followed by the underlying details. Group sync and the supergroups health check only look at supergroups whose group type is ALIAS. Supergroups of any other type in Rippling will not appear as Serval resources. When granting or revoking supergroup membership, Serval finds the Rippling worker by exact work email match. It fails with "No worker found with email: \[email]" when there is no match, and "Multiple workers found with email: \[email]" when the email is ambiguous. Serval user emails must match Rippling work emails exactly. Both the synced member list and Serval's grant and revoke operations work against the supergroup's inclusion-members list. If a user is blocked by the supergroup's exclusion-members list, adding them through Serval will not give them effective membership - Serval never modifies exclusion lists. Inclusion members without a work email in Rippling are skipped during membership sync and will not appear in the synced member list. All Serval traffic goes to rest.ripplingapis.com using bearer authentication with API Tier 1 access. Keys issued for Rippling's legacy platform API will not work - create the key under Rippling's v2 REST API access. Neither Company Name nor API Key (v2) is marked required, and there is no validation in the form or backend. Submitting blanks installs a connection that fails every health check - fill in both fields when connecting. The masked key (bullets plus last 4 characters) shown on the edit form is a placeholder. Leaving it as-is keeps the stored key, and so does replacing it with a blank value; pasting a complete new key replaces it. Similarly, a blank Company Name keeps the existing connection name. A worker is marked deactivated only when their linked Rippling user account is inactive. Workers without a linked user account are treated as active, and workers without a work email sync into Serval with an empty email. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Rippling integration. # Rootly Source: https://docs.serval.com/sections/integrations/rootly Connect Rootly, the incident management platform, to Serval with an API key so workflows can work with incidents, alerts, on-call schedules, and retrospectives on demand. ## About Rootly [Rootly](https://rootly.com) is an incident management platform covering incidents, alerts, on-call schedules, escalation policies, retrospectives, and status pages. Serval connects to Rootly with an API key that you generate in Rootly and paste into Serval. Workflows then call the Rootly API on demand, with Serval attaching your stored key to every request automatically. **Authentication:** API key (sent as a Bearer token on every request to the Rootly API). **Data sync:** On demand only. There is no background sync, no resource ingestion, and no prebuilt workflows are installed with this integration - all reads and writes happen when a workflow runs. ## What the Rootly integration enables | Capability | Description | | - | - | | Generic Rootly API access | A single "Rootly API request" action can call any of the 213 paths in Rootly's REST API v1. | | Incident management | List, read, create, and update incidents, plus incident types, roles, severities, sub-statuses, permission sets, and related action items. | | Alerts | List, read, and create alerts, acknowledge and resolve them, and work with related resources such as alert events, heartbeats, and live call routers. | | On-call and scheduling | Schedules, schedule rotations, escalation policies, escalation paths, on-call roles, and shifts - find out who is responsible during an incident. | | Catalog, services, and teams | Services, functionalities, teams, environments, and catalogs - the resources incidents map to. | | Retrospectives and post-mortems | Post-mortems, post-mortem templates, retrospective processes, process groups, and configurations. | | Other Rootly surfaces | Communications, Rootly-native workflows and workflow groups, status pages, dashboards, playbooks, webhooks, form fields and form sets, custom fields, secrets, users, and roles. | Anything defined in the [Rootly API](https://docs.rootly.com/api-reference/overview) can be accessed through Serval. ## Get your credentials You need a Rootly API key. Rootly offers three key types, and Serval inherits whatever the key can do - pick the narrowest type that covers what your workflows touch: * **Global API Key** - org-wide; assigned the On-Call and Incident Response role at generation. * **Team API Key** - Team Admin permissions over that team's entities, such as Schedules and Escalation Policies. * **Personal API Key** - inherits the permissions of the user who creates it. Full details are in the [Rootly API reference](https://docs.rootly.com/api-reference/overview). Sign in to Rootly, click the Organization dropdown in the top navigation, and select **Organization Settings**. Navigate to **API Keys** in the settings menu. Click **Generate New API Key** and select the API Key Type (Global, Team, or Personal) that matches your integration needs. Give the key a descriptive name, e.g. "Serval Production Integration", and generate it. Copy the token value right away - Rootly shows it only once. Rootly displays the API key a single time at creation. If you navigate away without copying it, you will need to generate a new key. The key inherits the permissions of its type. If your workflows only touch one team's schedules and escalation policies, a Team API Key is enough; reserve Global keys for org-wide automation. ## Connect in Serval In Serval, open the integrations page and choose **Rootly** to open the connect form. Optionally fill in **Instance Name (optional)** - "A name to distinguish between different Rootly instances (e.g., 'Production Rootly')". If you leave it blank, the connection is named "Rootly". Fill in **API Key** - "Your Rootly API key. Generate this in Organization Settings > API Keys". This is a password-style field; after saving, Serval shows it masked, with only the last 4 characters visible. Submit the form. Serval does not test the key against Rootly at save time, so a mistyped key is accepted here. If the save itself fails you will see a general error such as "Failed to connect service" or "Failed to install integration" - check your input and try again. When you edit an existing connection, the API Key shows as a read-only masked value (bullet characters plus the last 4 characters of your key) with a control to replace it. Leaving it untouched - or starting a replacement and submitting nothing - keeps the stored key; only a non-empty new value replaces it. The Instance Name field comes pre-filled with the current name: type a new name to rename the connection, but note that clearing the field and saving keeps the existing name rather than blanking it. ## Verifying the connection The Rootly integration has no automated health checks in Serval, and the key is not validated when you save, so there is no pass/fail status to look for. To verify the connection: 1. Create or run a simple workflow that reads Rootly data - for example, one that lists incidents or schedules. 2. If the workflow returns Rootly data, the key works. 3. If it fails with an authentication error, the key was likely revoked in Rootly or pasted incorrectly - generate a fresh key and update the connection. A successful read only proves the key is valid - it does not prove the key can reach every resource. If a basic read works but a workflow gets a permission error on a specific resource (for example, another team's schedules), the key's type or owner lacks access in Rootly. See "Key permissions are inherited" below. ## Gotchas and troubleshooting Rootly has no health checks in Serval and the key is not checked at connect time, so a mistyped or revoked key is not caught when you save - it surfaces the first time a workflow calls the Rootly API. Generate a new key in Rootly, enter it in the connection settings, and re-run the workflow. Serval does not add or remove any permissions - the connection can do exactly what the key can do in Rootly. A Global key carries the On-Call and Incident Response role org-wide, a Team key has Team Admin rights over that team's entities, and a Personal key mirrors its creator. If a workflow gets a 403 on a specific resource, regenerate the key under an account or key type with the needed scope and update the connection. Requests to Rootly are sent and received in the JSON:API format rather than plain JSON. Data you send when creating or updating records must be structured as a JSON:API document, and results come back wrapped in a "data" object containing an id, a type, and the record's attributes. Workflow builders who expect flat JSON will find the fields one level deeper than anticipated. Rootly list responses come back in pages, controlled by page number and page size parameters. To retrieve everything, workflows request page 1, then page 2, and so on until a page comes back with an empty data array. Serval attaches your API key only to requests addressed to api.rootly.com, and requests to any other host are rejected. If a workflow request fails before reaching Rootly, check that it targets the Rootly API rather than another URL. Rootly has no per-customer subdomains, so every connection points at the same Rootly service. If you connect more than one Rootly organization or key, set a distinct Instance Name on each - otherwise they all display as "Rootly" and are hard to tell apart in the UI. Serval keeps using the stored key until it stops working. If you revoke or rotate the key in Rootly, workflows will start failing until you paste the new key into the connection. When rotating, edit the connection, replace the API Key with the new value, and save - the Instance Name can stay as is. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Rootly integration. # RSA SecurID Source: https://docs.serval.com/sections/integrations/rsa Connect Serval to the RSA SecurID Authentication API (RSA ID Plus / Cloud Authentication Service) so workflows can run multi-factor authentication flows - starting, verifying, checking, and canceling MFA attempts on demand. ## About RSA SecurID The RSA SecurID integration connects Serval to the RSA SecurID Authentication API, the MFA service provided by RSA ID Plus / Cloud Authentication Service. An admin supplies an API URL, Access ID, and Client Key; Serval stores the Client Key encrypted and attaches it automatically to every call it makes on your behalf. Workflows then use a single "RSA SecurID API request" action to drive the full MFA flow. This connector is currently marked **Beta** in Serval's integrations UI, and the connection is identified by the host of your API URL (for example, your-tenant.securid.com). **Authentication:** API key - the Client Key is sent as an authentication header on every request. **Data sync:** None. The integration is on-demand only - no background sync, webhooks, or polling. Outside your workflow runs, the only traffic is the connection health check, which runs when you trigger it and after you save configuration changes. ## What the RSA SecurID integration enables | Capability | Description | | - | - | | RSA SecurID API request | A single workflow action that calls the RSA Authentication API with your credentials attached automatically. | | Initialize an authentication attempt | Start an MFA attempt for a user and get back the attempt ID and the challenge methods the user can complete. Supports assurance levels (ALLOW / LOW / MEDIUM / HIGH / DENY), policy selection, and pre-collected credentials for single-step auth. | | Verify authentication credentials | Submit collected credentials (password, OTP, and so on) for an attempt. Responses report SUCCESS, FAIL, ERROR, CHALLENGE (more input needed), or IN\_PROCESS (poll again, for example while a push approval is pending). | | Check authentication status | Look up or confirm the result of a previous authentication attempt from another session using its attempt ID. | | Cancel an authentication attempt | Explicitly cancel a pending attempt (for user action or timeout). | | Fetch localized prompt resources | Retrieve translated prompt text for rendering authentication prompts in the user's language. | | AI context | Serval's AI knows the RSA SecurID Authentication API endpoint catalog and can help you build workflows against it. | Anything defined in the [RSA SecurID Authentication API](https://community.securid.com/s/rsa-id-plus-documentation/mfa-authentication-api) can be accessed through Serval. ## Get your credentials You need three values from RSA: the Authentication API base URL, an Access ID, and a Client Key (RSA also calls it the Access Key). For RSA ID Plus / Cloud Authentication Service, all three come from the Cloud Administration Console. RSA's official guide is [Manage the RSA Authentication API Keys](https://community.securid.com/s/article/Manage-the-RSA-Authentication-API-Keys-Legacy-Clients-09a51852). Sign in as an administrator. Navigate to **Platform > API Access Management**. (Older console versions list these keys under My Account > Company Settings instead.) This tab lists your Authentication API keys (up to 10 can exist). Add a new key and copy the key value - this is the **Client Key** you will paste into Serval. RSA also calls it the Access Key. Record the **Access ID** associated with the key configuration. On the same tab, use **Copy URL** under the RSA SecurID Authentication API REST URL - this is the **API URL** for the Serval connect form. Serval only sends credentials to cloud-hosted RSA endpoints on a subdomain of securid.com. Self-hosted RSA Authentication Manager (where the equivalent values live under Security Console > Setup > System Settings > RSA SecurID Authentication API) uses custom hostnames that Serval will not authenticate to - cloud-hosted endpoints are the supported path. RSA Authentication API keys do not expire. Store the key securely and plan manual rotation - RSA recommends rotating roughly every 90 days. ## Connect in Serval Find **RSA SecurID** in Serval's integrations list (it is labeled Beta) and open the connect form. Paste your tenant's Authentication API base URL, for example [https://your-tenant.securid.com](https://your-tenant.securid.com). The helper text reads "The RSA SecurID Authentication API base URL (e.g., [https://your-tenant.securid.com](https://your-tenant.securid.com))". Leaving it empty shows "This field is required". The https\:// requirement is only checked when you submit: a plain http\:// URL is rejected with "Failed to install integration: Invalid RSA SecurID configuration: API URL must start with https\://". The helper text reads "The Access ID from the RSA REST configuration interface". Leaving it empty shows "This field is required". A masked password field. The helper text reads "The client-key (Access Key) from the RSA REST configuration interface". This field has no inline emptiness check - submitting without it fails with "Failed to install integration: Invalid RSA SecurID configuration: client key is required". Click **Submit**. Serval stores the Client Key encrypted and names the connection after the host of your API URL. When editing an existing connection, the Client Key shows as a masked value (bullets plus its last 4 characters) - use the **Replace** button, or the pencil icon on the connection's settings page, to enter a new one. An untouched or blank Client Key keeps the current value, and the same applies to a cleared API URL or Access ID: blank means keep existing. Only paste a complete new Client Key when you are rotating credentials. If an update is rejected (for example a non-https API URL), the settings page shows "Failed to update configuration". ## Verifying the connection The integration runs one health check, **Validate RSA SecurID API Connection**. It makes a lightweight, read-only call to RSA's language-resources endpoint using your stored credentials, which confirms both that the API URL is reachable and that the Client Key is accepted. * On success: "Successfully connected to RSA SecurID API." * On failure: "Unable to connect to RSA SecurID API. Please verify your API URL and client key are correct." If the health check is green but an authentication workflow seems stuck, it is usually waiting on the end user rather than a broken connection: a pending push approval returns an in-process status that the workflow must poll, and attempts expire after a timeout (180 seconds by default). ## Gotchas and troubleshooting Serval attaches credentials only when the request host is a subdomain of securid.com (for example, [https://your-tenant.securid.com](https://your-tenant.securid.com)). Self-hosted RSA Authentication Manager at a custom hostname will not receive credentials, so every call fails. The bare apex securid.com (no subdomain) also does not qualify. Outbound calls authenticate with the Client Key alone. The Access ID is required by the form and saved with the connection, but it is never included in API requests - HMAC request signing (which uses the Access ID) is not supported. If your RSA deployment is configured to require HMAC mode, requests will be rejected. The form's only inline checks are that the API URL and Access ID are filled in. The https\:// requirement is enforced by Serval when you click Submit: on first connect the failure reads "Failed to install integration: Invalid RSA SecurID configuration: API URL must start with https\://", while a rejected update on the connection's settings page shows "Failed to update configuration". On edit, the Client Key appears as bullets plus its last 4 characters, with a Replace button (or pencil icon) to enter a new value. Leaving it untouched or blank preserves the current key, and the same applies to the API URL and Access ID - blank means keep existing. Paste a complete new key only when rotating credentials; never retype the masked placeholder as if it were the key (Serval's form discards placeholder-shaped values before submitting, so they cannot overwrite the stored key through the UI). Initializing an attempt returns an attempt ID and the user's available challenge methods; verifying may come back with CHALLENGE (more input needed) or IN\_PROCESS (poll again, for example while a push approval is pending) before reaching SUCCESS, FAIL, or ERROR. Initialize and verify calls carry a message context - the attempt ID, a new message ID, and a reply-to echoing the server's previous message ID - while status checks and cancellation reference just the attempt ID. Workflows that drive authentication need to implement this loop, and attempts time out (180 seconds by default). RSA SecurID is marked Beta in the connect UI. Behavior and coverage may evolve faster than mature connectors - report anything unexpected to support. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your RSA SecurID integration. # SailPoint Source: https://docs.serval.com/sections/integrations/sailpoint SailPoint is an identity security platform - Serval connects to both IdentityIQ (on-premises) and Identity Security Cloud, and this page helps you pick the right guide. ## About SailPoint SailPoint is an identity security platform that helps organizations manage and govern access to applications and data. Serval supports two SailPoint products: * **[IdentityIQ](/sections/integrations/sailpoint-identityiq)** - On-premises identity governance platform with SCIM API access * **[Identity Security Cloud (ISC)](/sections/integrations/sailpoint-identitysc)** - Cloud-based identity security platform (formerly IdentityNow) ## What the SailPoint integration enables | Capability | Description | | - | - | | Access Management | Query and manage user identities, accounts, and entitlements | | Automation | Automate access reviews, provisioning, and governance workflows | | Act as the requesting user | On Identity Security Cloud, workflows can optionally call the API as the individual user who triggered them, under that user's own governance rights - see [per-user OAuth](/sections/integrations/sailpoint-identitysc#per-user-user-auth-oauth) | ## Which product should I connect? Serval lists the two SailPoint products as separate integrations: find **SailPoint IdentityIQ** or **SailPoint Identity Security Cloud** in your team's integrations and click **Connect** on the one that matches your product. | Product | Deployment | Authentication | Guide | | - | - | - | - | | IdentityIQ | On-premises | Username and password | [Setup guide](/sections/integrations/sailpoint-identityiq) | | Identity Security Cloud | Cloud | Personal Access Token, plus optional per-user OAuth | [Setup guide](/sections/integrations/sailpoint-identitysc) | If you are unsure which product your organization uses, check with your identity team. IdentityIQ is typically self-hosted, while Identity Security Cloud is accessed at `[tenant].identitynow.com`. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your SailPoint integration. # SailPoint IdentityIQ Source: https://docs.serval.com/sections/integrations/sailpoint-identityiq Connect SailPoint IdentityIQ to Serval with a service account so workflows and the AI agent can read and manage identities and accounts, query entitlements and policy violations, and launch IdentityIQ workflows on demand. ## About SailPoint IdentityIQ SailPoint IdentityIQ is SailPoint's on-premises identity governance platform. Serval connects to your IdentityIQ server through its SCIM API using a username and password for a service account on your instance - there is no OAuth flow or sign-in redirect. Serval stores the credentials securely and sends them, as basic authentication, only with requests to the IdentityIQ server you configure. The integration is request-driven: Serval workflows and the AI agent read users, accounts, entitlements, roles, and policy violations, manage users and accounts, and launch IdentityIQ workflows, all on demand. If you use SailPoint's cloud product instead, see the [SailPoint Identity Security Cloud setup guide](/sections/integrations/sailpoint-identitysc) - or start from the [SailPoint overview](/sections/integrations/sailpoint) if you are not sure which one you have. **Authentication:** Basic authentication - a dedicated IdentityIQ service account username and password, stored securely by Serval. **Data sync:** No background or scheduled sync. All data access happens on demand when a workflow or the AI agent makes a request. ## What the SailPoint IdentityIQ integration enables | Capability | Description | | - | - | | Full SCIM API access | Workflows and the AI agent make typed requests across the IdentityIQ SCIM API surface: users, accounts, entitlements, roles, applications, alerts, policy violations, policy violation checks, launched workflows, workflows, task results, object configs, resource types, schemas, and the service provider configuration. | | Identity and account management | Query users, accounts, and entitlements with SCIM filters and pagination, and create, update, or delete users and accounts - the basis for access reviews and governance automations. | | Workflow launch and task tracking | Launch IdentityIQ workflows and inspect launched workflows and task results for provisioning and governance operations. | | Policy violation visibility | Read policy violations and run policy violation checks for compliance-driven automations. | | Connection health checks | Three built-in checks (Test Connection, List Users, List Accounts) verify authentication and read permissions from the app page. | Anything defined in the [SailPoint IdentityIQ SCIM API](https://developer.sailpoint.com/docs/api/iiq/) can be accessed through Serval. ## Get your credentials Serval needs three things: your IdentityIQ server hostname, and the username and password of a service account that can use the SCIM API. There is no OAuth app, API token, or client credentials to create. SailPoint's API documentation lives on the [SailPoint Developer Community](https://developer.sailpoint.com/). Ask your IdentityIQ administrator to confirm the SCIM API is enabled on your instance and reachable from outside your network (or via your allowed network path). The SCIM address is [https://identityiq.company.com/identityiq/scim/v2](https://identityiq.company.com/identityiq/scim/v2), with your own hostname in place of the example - if that address answers, Serval can reach it. Create (or pick) a service account in IdentityIQ with permission to use the SCIM API and read the resources you plan to automate against - users, accounts, entitlements, and so on. Record the hostname exactly as Serval should call it - for example identityiq.company.com. Hostname only: no https\:// prefix and no trailing path. Use a dedicated service account, not a personal admin account. Serval replays the stored username and password on every request, so if the account's password changes in IdentityIQ - for example when an employee rotates their own credentials - the connection breaks until the password is updated in Serval. ## Connect in Serval In Serval, go to **Integrations**, open the **All integrations** tab, find **SailPoint IdentityIQ**, and click **Connect**. (The [SailPoint overview](/sections/integrations/sailpoint) explains the difference between the two SailPoint products.) **Instance URL** is required (marked with an asterisk) and described as "Your IdentityIQ server hostname (e.g. identityiq.company.com)". Enter the hostname only - no https\:// prefix and no path. Leaving it empty shows "This field is required". **Username** is required and described as "IdentityIQ admin username". Use your dedicated service account. Leaving it empty shows "This field is required". **Password** is required and described as "IdentityIQ admin password". It is entered as a hidden password field. The form does not flag a missing password before submitting, so double-check it is filled in - an empty password is only caught later, when the health checks fail. Click **Submit** (the button reads "Submitting..." while saving). If installation fails, an error appears starting with "Failed to install integration", with details appended when available. Serval does not validate the hostname format or test the credentials at save time - typos only surface when the health checks run. Run them right after connecting (see below). To edit the connection later, open the **API Integration** tab on the SailPoint IdentityIQ app page. The form comes pre-filled: Instance URL and Username show their saved values, and the saved password appears masked - bullet characters plus its last 4 characters - next to a **Replace** button. To rotate the password, click **Replace** and type the complete new password; leaving it untouched (or blank) keeps the saved password. The **Update** button stays disabled until you change something. A successful save shows "Configuration updated successfully"; failures show "Failed to update configuration". ## Verifying the connection Run the health checks from the **API Integration** tab on the SailPoint IdentityIQ app page. Re-run them whenever you update the connection's credentials. * **Test Connection** - reads the SCIM service configuration to verify Serval can reach your instance and sign in. Success: "Successfully connected to SailPoint IdentityIQ SCIM API." Failure: "Unable to connect to SailPoint IdentityIQ. Please verify your instance URL and credentials." If the server rejects the credentials specifically (a 401 Unauthorized response), the failure reads "Authentication failed. Please verify your IdentityIQ username and password are correct." * **List Users** - asks the SCIM API for a single user to verify the credentials can read user data. Success: "Successfully listed users. Total users found: \[number]." (the count reads "unknown" if your server does not report a total). Failure: "Unable to list users. Please verify the configured credentials have permission to read user data." * **List Accounts** - asks the SCIM API for a single account to verify the credentials can read account data. Success: "Successfully listed accounts. Total accounts found: \[number]." (or "unknown"). Failure: "Unable to list accounts. Please verify the configured credentials have permission to read account data." A green **Test Connection** with a failing **List Users** or **List Accounts** means Serval can reach the server and sign in, but the service account lacks SCIM read permission on that resource. Fix the account's permissions in IdentityIQ - the Instance URL and password are already correct. ## Gotchas and troubleshooting Enter only the server hostname (for example identityiq.company.com) - no https\:// prefix and no path. Serval automatically adds the SCIM API path to every request, so including any path in the Instance URL produces malformed request addresses and the Test Connection check fails with "Unable to connect to SailPoint IdentityIQ. Please verify your instance URL and credentials." Because IdentityIQ is self-hosted, Serval can only connect if your server is reachable from Serval and the SCIM API is enabled on the instance. If either is not true, Test Connection fails with "Unable to connect to SailPoint IdentityIQ. Please verify your instance URL and credentials." Ask your IdentityIQ administrator to confirm both, then re-run the check. Serval sends the stored username and password on every request. If the service account's password is rotated in IdentityIQ, requests start failing and Test Connection reports "Authentication failed. Please verify your IdentityIQ username and password are correct." Update the password on the connection in Serval (click **Replace** next to the masked value on the **API Integration** tab) to restore it. Using a dedicated service account prevents an individual's routine credential rotation from taking the integration down. On the **API Integration** tab, Instance URL and Username come pre-filled with their saved values - edit them in place. Clearing either one blocks the save with "Instance URL is required" or "Username is required". The saved password is shown masked with a **Replace** button: click it and type the complete new password to rotate it, or leave the password untouched (or blank) to keep the saved one. Saving does not re-test the credentials, so re-run the health checks from the same tab afterward to confirm the new values work. This page covers the on-premises product, IdentityIQ. If your organization uses SailPoint's cloud platform (Identity Security Cloud, formerly IdentityNow), the connection works differently - see the [SailPoint Identity Security Cloud setup guide](/sections/integrations/sailpoint-identitysc), or use the [SailPoint overview](/sections/integrations/sailpoint) to confirm which one you have before connecting. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your SailPoint IdentityIQ integration. # SailPoint Identity Security Cloud Source: https://docs.serval.com/sections/integrations/sailpoint-identitysc Connect Serval to SailPoint Identity Security Cloud (ISC) so workflows can read identities and accounts, govern access, and automate access requests and certifications through the ISC V2025 API. ## About SailPoint Identity Security Cloud SailPoint Identity Security Cloud (ISC), formerly IdentityNow, is SailPoint's SaaS identity governance platform. Serval connects to a single ISC tenant using the Client ID and Client Secret from a SailPoint Personal Access Token, and gives your workflows access to the full ISC V2025 REST API - 537 endpoints covering identities, accounts, access profiles, certifications, sources, and more. Serval only ever sends these credentials to your tenant's API host under api.identitynow\.com. ISC is one of two SailPoint products Serval supports: if you run the on-premises product, see [SailPoint IdentityIQ](/sections/integrations/sailpoint-identityiq) instead, or start from the [SailPoint overview](/sections/integrations/sailpoint). **Authentication:** OAuth 2.0 client credentials, using a SailPoint Personal Access Token (Client ID + Client Secret). Serval exchanges these for short-lived access tokens automatically - the only credential to manage over time is the token itself, which carries an expiration date you set in SailPoint (6 months by default). An optional, feature-flagged per-user OAuth path lets certain actions run as the acting end user. **Data sync:** On-demand only. There is no scheduled background sync, no entity ingestion, and no prebuilt install workflows - your workflows call the ISC API at run time. ## What the SailPoint Identity Security Cloud integration enables | Capability | Description | | - | - | | Read identities | List and read identities, public identities, identity profiles, and historical identities. | | Read accounts | List and read accounts and their entitlements, including account lifecycle operations. | | Govern access profiles and entitlements | Query and manage the access profiles and entitlements that back access requests, certifications, and provisioning. | | Automate access requests and certifications | Submit and track access requests, access-request approvals, certifications, and certification campaigns. | | Manage sources, roles, and workgroups | The API's largest families - sources, roles, role mining, certifications, work items, identities, and accounts - are all reachable. | | Call any V2025 API endpoint | A generic API request action reaches any of the 537 endpoints (781 operations) in the bundled V2025 spec that your token is authorized for. | Anything defined in the [SailPoint V2025 API](https://developer.sailpoint.com/docs/api/v2025/) can be accessed through Serval. ## Get your credentials Serval authenticates with a SailPoint **Personal Access Token (PAT)**. Creating one gives you the Client ID and Client Secret that Serval needs. See [SailPoint's Personal Access Tokens documentation](https://documentation.sailpoint.com/saas/help/common/api_keys.html) for full details, and [SailPoint's API authentication guide](https://developer.sailpoint.com/docs/api/authentication) for how the client credentials grant works behind the scenes. A PAT can never do more than the user who creates it, and it is further limited by the scopes you select when you create it - Serval requests no additional scopes of its own. Generate the token from a user whose governance rights cover everything you want Serval to do, and select **sp:scopes:all** unless you deliberately want to restrict it. Sign in as the user whose permissions the integration should use. Select the user icon in the upper-right corner, choose **Preferences**, then select **Personal Access Tokens** from the left menu - or navigate directly to `https://[tenant].identitynow.com/ui/d/user-preferences/personal-access-tokens`. Click **New Token** and describe the token's purpose in the **What is this token for?** field (for example "Serval Integration"). Set the expiration date deliberately: it defaults to 6 months out, and leaving it blank creates a token that never expires. Use the scope toggles to select **sp:scopes:all**, which authorizes the token for everything its creator's access level allows. If you select no scopes at all, SailPoint assigns a default scope that only reaches endpoints requiring no authorization - Serval's health checks will fail with a token like that. Then click **Create Token**. Copy the **Client ID** and the **Secret** (this is the Client Secret). You will paste both into Serval. The Secret is shown only once, at creation. If you close the dialog without saving it, you must create a new token. SailPoint also limits each user to 10 Personal Access Tokens - the **New Token** button is disabled once you hit the cap - so delete unused tokens before creating new ones. Your tenant name is the subdomain of your ISC URL - `acme-corp` from `acme-corp.identitynow.com`. Admins can confirm it by opening the **Dashboard** dropdown, selecting **Overview**, and finding the Org Name in the Org Details section. If your org signs in through a vanity URL, the subdomain is not your tenant name - use the Org Name from the dashboard, or open `https://[tenant].api.identitynow.com/oauth/info` in a browser and use the `tenantName` value it returns. ## Per-user (user-auth) OAuth By default every workflow call runs as the service account (the PAT above). Optionally, workflows can call the ISC API **as the individual user who triggered them** - under that user's own governance rights, with that user as the audit identity. Users connect their own SailPoint account to Serval once, then actions marked "as user" use their credential. Personal Access Tokens only support the client-credentials grant, so per-user auth needs a dedicated OAuth client in your tenant: In ISC, go to **Admin > Global > Security Settings > API Management** and create a new API client with the **Authorization Code** and **Refresh Token** grant types (you can also create it through the [oauth-clients API](https://developer.sailpoint.com/docs/api/v3/create-oauth-client)). Add the following as a redirect URL on the client: ``` https://svflow-auth-config.api.serval.com/sailpoint-identitysc/user/oauth/callback ``` If your Serval tenant is on the EU shard, use `https://api.eu1.serval.com/v1/svflow-authconfig/sailpoint-identitysc/user/oauth/callback` instead (ask [support@serval.com](mailto:support@serval.com) if you're unsure which region you're on). Edit the SailPoint ISC connection in Serval and paste the client's ID and Secret into **User-Auth OAuth Client ID** and **User-Auth OAuth Client Secret**. In **User-Auth OAuth Scopes**, click **Choose scopes**. Serval uses the connection's Personal Access Token to read the configured OAuth client's allowed scopes. Search the list and select the scopes your workflows need, then click **Done** and save the connection. Remove selected scopes using their chips. If SailPoint denies the lookup or the client can't be reached, choose **Browse documented scopes** to search a catalog from SailPoint's published API specifications. These suggestions aren't verified for your client: confirm that your OAuth client allows them. **Enter scopes manually** is available for scopes missing from the catalog. New connections start with `sp:scopes:all` selected. Existing connections keep their saved scopes. To restrict the request, remove `sp:scopes:all` and select the approved scopes your workflows need. At least one scope is required: **Update** stays disabled while the selection is empty. These fields appear when per-user authentication is enabled for your organization. They don't change the service account's PAT scopes. After changing scopes, have users reconnect their SailPoint accounts. Saving the connection doesn't revoke or change existing tokens. Each user connects their SailPoint account the first time a workflow needs it - Serval fails the run with a personal connect link if they haven't. Tokens are scoped by ISC to the connecting user's own access level. ## Connect in Serval In Serval, go to your team's integrations, find **SailPoint Identity Security Cloud**, and click **Connect**. Enter just the tenant identifier - helper text reads "Your ISC tenant name (e.g. acme-corp from acme-corp.api.identitynow\.com)". Do not paste a full URL: there is no format check, and Serval uses the value verbatim to build the API address, so a URL here breaks the connection. Leaving it blank shows "This field is required". Paste the Client ID from your Personal Access Token - helper text reads "Client ID from your Personal Access Token". Leaving it blank shows "This field is required". Paste the Client Secret from the same token into this password field - helper text reads "Client secret from your Personal Access Token". Unlike the other two fields, the form will not stop you from submitting with this one empty - the mistake only surfaces when the health checks run, so double-check the secret made it in. Click **Submit**. Serval stores the credentials and names the connection after your tenant. If installation fails, the form shows "Failed to install integration" (with details appended when available). Serval does not test the credentials when you save - a mistyped tenant name or secret is accepted at save time and only surfaces when the health checks run. Run them right after connecting (see below). When you edit an existing connection, the form opens pre-filled with your saved values: Tenant Name and Client ID appear as entered, and the Client Secret appears masked (bullet characters plus its last 4 characters) next to a **Replace** button. To rotate the secret, click **Replace** and paste the complete new secret into the "Enter new value" box. Credentials you leave untouched, or clear to blank, keep their stored values - so you can rotate just the secret without re-entering the Tenant Name or Client ID. ## Verifying the connection The integration runs three health checks: * **Test Connection** - makes a minimal read of public identity data to confirm Serval can authenticate and reach your tenant's API. On success: "Successfully connected to SailPoint Identity Security Cloud API." If your credentials are rejected: "Authentication failed. Please verify your Client ID and Client Secret are correct." For any other failure (for example a mistyped tenant name): "Unable to connect to SailPoint Identity Security Cloud. Please verify your tenant name and credentials." * **List Identities** - makes a minimal identity read to confirm the credentials can see identity data. On success: "Successfully listed identities." On failure: "Unable to list identities. Please verify the configured credentials have permission to read identity data." * **List Accounts** - makes a minimal account read to confirm the credentials can see account data. On success: "Successfully listed accounts." On failure: "Unable to list accounts. Please verify the configured credentials have permission to read account data." If Test Connection is green but a workflow step fails with a permission (403) error, your credentials are valid but the token lacks rights for that specific operation. Recreate the token from a user with the needed governance authority - with **sp:scopes:all** selected - and update the connection. The List Identities and List Accounts checks surface the most common read-permission gaps directly. ## Gotchas and troubleshooting Check **User-Auth OAuth Scopes** against the scopes allowed by your SailPoint OAuth client. Use **Choose scopes** to replace `sp:scopes:all` with the approved scopes your workflows need, save the connection, and retry sign-in. The requested scopes must be allowed by SailPoint; changing this field doesn't grant additional permissions to the client or user. Serval builds the API address directly from the Tenant Name field with no format validation. Enter just the identifier (`acme-corp`), not `https://acme-corp.identitynow.com`. If your org uses a vanity URL, recover the real tenant name from the Org Name on your dashboard's Overview page, or from the `tenantName` value at `https://[tenant].api.identitynow.com/oauth/info`. A Personal Access Token never exceeds the governance authority of the ISC user who created it, and it is further narrowed by the scopes selected at creation - Serval requests no additional scopes. 403 Forbidden responses mean the token lacks rights for that operation: recreate it from a user with the needed authority, select **sp:scopes:all**, and update the connection. The List Identities and List Accounts health checks surface this directly. SailPoint displays the Secret only at token creation, and each user can hold at most 10 Personal Access Tokens - the **New Token** button is disabled at the cap. Store the secret before closing the dialog; if it is lost, create a new token and update the connection. When you create a PAT, SailPoint sets its expiration 6 months out unless you change it (a blank expiration date means the token never expires). When the token lapses, the connection's health checks start failing with authentication errors even though nothing changed in Serval. You can extend the expiration date in SailPoint before it lapses - SailPoint even lets you restore an expired token by updating its date for up to 3 months afterward - or create a new token and update the connection's Client ID and Client Secret. The edit form opens pre-filled. The Client Secret shows as a masked, read-only value with a **Replace** button - click **Replace** and paste the full new secret to rotate it. Tenant Name and Client ID stay as saved unless you type over them, and credentials you clear to blank also keep their stored values, so a secret rotation never requires re-entering the rest of the form. A new Tenant Name re-derives the API address and renames the connection. The existing Client ID and Client Secret are kept unless you also replace them, so after a tenant change you almost always need to supply credentials from a PAT created in the new tenant too. For builders: the generic API request action automatically adds the `v2025` version prefix to every path, so pass paths without it. Path parameters use curly-brace placeholders filled in through the action's path parameters, not colon-style. List endpoints paginate with `limit` and `offset`; requesting an exact total count is expensive on large tenants, so ask for it only when you need it. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your SailPoint Identity Security Cloud integration. # Salesforce Source: https://docs.serval.com/sections/integrations/salesforce Salesforce is a cloud-based CRM platform - Serval connects to your org to sync Service Cloud Cases as tickets and run on-demand actions against the Salesforce API from your workflows. ## About Salesforce Salesforce is a cloud-based CRM platform for managing customer relationships, sales pipelines, support cases, and more. The Serval Salesforce integration connects securely to your Salesforce org and does two things: it syncs **Service Cloud Cases** with Serval tickets (one-way or two-way), and it lets your workflows reach the Salesforce API on demand. The workflow surface acts as a live passthrough - each request runs only when a workflow asks for it, so accounts, contacts, cases, opportunities, custom objects, and SOQL queries are all reachable. Because every call runs as the user you assign during setup, that user's permissions determine what Serval can read or change. **Authentication:** OAuth 2.0 Client Credentials Flow **Data sync:** When ticket sync is enabled, Serval polls your org for Case and CaseComment changes roughly every 30 seconds. Everything else is on-demand - workflow actions call the API only when a workflow runs, and Serval stores no Salesforce record data beyond the tickets it syncs. ## What the Salesforce integration enables | Capability | Description | | - | - | | Ticket sync | Native sync between Serval tickets and Salesforce Service Cloud Cases - one-way or two-way, including comments, statuses, priorities, requesters, and assignees. Optionally scoped to a single Case Queue. See [Ticket sync](#ticket-sync). | | Salesforce API request | A single built-in action that sends a request to your connected Salesforce org and returns the response. Workflows specify what to do (the operation, the target, and any details to send), so it can query and manage accounts, contacts, cases, opportunities, custom objects, and more. | | Full Salesforce API access | Because the action is a generic passthrough, any part of the Salesforce API your connected app is permitted to use is reachable from workflows - including querying records with SOQL. | | Connection healthcheck | A built-in test that confirms Serval can authenticate to your org and reports how many API versions are available. | Anything defined in the [Salesforce REST API](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_rest.htm) can be accessed through Serval. ## Ticket sync Connecting Salesforce also enables native ticket sync between Serval tickets and Salesforce **Service Cloud Cases**. Serval polls your org for Case changes, ingests new and updated Cases as Serval tickets, and - in two-way mode - writes Serval-side changes back as Case updates and CaseComments. Sync can cover every Case in the org or be scoped to a single Case Queue. ### What syncs | Serval | Salesforce | Notes | | - | - | - | | Ticket title and description | Case Subject and Description | Descriptions are captured when the linked ticket or Case is first created; later description edits are not overwritten in either direction. | | Public replies | Published CaseComments | Published comments from Salesforce arrive as public replies on the Serval ticket, and vice versa. | | Internal notes | Unpublished CaseComments | Unpublished comments stay agent-only in Salesforce, and Serval internal notes go up as unpublished comments - neither side leaks onto the customer-visible thread. | | Status | Case Status picklist | Mapped per your configuration. Serval reads your org's actual Status picklist values live, so custom statuses appear in the mapping UI. A Serval status with no mapping is never written to Salesforce - the Case keeps whatever status it has. | | Priority | Case Priority | High, Medium, and Low map automatically. Salesforce's standard Priority picklist has no Urgent, so Serval's Urgent is written to Salesforce as High — but the Serval ticket keeps its Urgent priority (the sync recognizes the collapse and won't downgrade it). Custom or unmapped Salesforce priorities are left alone rather than overwritten. | | Requester | Case Contact | The Case Contact becomes the Serval requester; Web-to-Case submissions without a Contact fall back to the Case's SuppliedEmail, then to the case creator. Cases created from Serval link the requester's Salesforce Contact when exactly one Contact matches their email. | | Assignee | Case Owner | Owner and assignee sync two-way. A human Serval assignee is written back to the Case Owner, resolved to a Salesforce User by email (a unique, active match is required). AI-owned tickets leave the Case Owner untouched, and queue-owned Cases arrive unassigned. When Serval sets an owner, it suppresses your org's Case assignment rules so they don't override the write. | | Attachments | ContentVersion + ContentDocumentLink | Files on public replies upload to the Case (up to about 37.5 MB each). Inline images and files attached to internal notes are not uploaded. | The Salesforce API posts every CaseComment as the Connected App's **Run As** user - it cannot impersonate authors. Human-authored Serval messages are therefore prefixed with an attribution header, `[Comment from: Name ]`, so agents in Salesforce can see who actually wrote them. Messages authored by the Serval AI agent carry `[Comment from: (AI Agent)]` instead. The header is stripped again when the comment syncs back, so it never appears on the Serval side. ### Set up ticket sync Ticket sync is configured per team on top of an existing Salesforce connection. Follow [Get your credentials](#get-your-credentials) and [Connect in Serval](#connect-in-serval) below if you haven't already. Ticket sync uses the same Connected App connection - no extra credentials are needed. In the Salesforce app's settings in Serval, open the team's **Salesforce Case Syncing** configuration. Optionally select a Case Queue - Cases owned by that queue sync to this team, and Cases Serval creates are placed in it. Leave it on **All Cases** to sync every Case in the org; Cases Serval creates are then left to your org's assignment rules. Map each Serval status to a Salesforce Case Status. Serval fetches your org's actual Status picklist (including custom values), so the options match what your agents see. Statuses you leave unmapped are simply never written to Salesforce. Pick how tickets should sync - selectively per ticket, automatically on escalation, for all new tickets (full two-way sync), or by importing existing Cases - and whether the sync is one-way or two-way. Save to start syncing. ### Required Salesforce permissions Ticket sync runs entirely as the Connected App's **Run As** user, so that user's profile or permission sets must cover the objects the sync touches: | Permission | Why it's needed | | - | - | | **API Enabled** (system permission) | All sync traffic goes through the REST API. | | **Case** - Read, Create, Edit | Poll for Case changes, create Cases from Serval tickets, and write status and priority updates. | | **CaseComment** - Read, Create | Sync the conversation in both directions. | | **Contact** - Read | Resolve the Case Contact to the Serval requester. | | **User** - Read | Resolve the Case Owner to the Serval assignee and attribute comments. | | **Group** / **QueueSobject** - Read | List the org's Case Queues in the queue picker and scope polling to the selected queue. | | **CaseStatus** - Read | Read the org's Case Status picklist values for status mapping. | ### Polling cadence and API usage Serval polls your org for changed Cases and CaseComments roughly every **30 seconds** (a SOQL query filtered on `SystemModstamp`). There are no webhooks in this version, so changes made in Salesforce can take up to about 30 seconds to appear in Serval; changes made in Serval are pushed to Salesforce as they happen. Salesforce enforces org-wide **daily API request limits**, and Serval's polling consumes part of that allocation around the clock while ticket sync is enabled. If your org runs close to its limit, account for the polling traffic when budgeting API usage. ### Limitations * **No attachments.** Files attached on either side do not sync. * **No real-time webhooks.** Sync is polling-based, with roughly 30 seconds of latency for changes originating in Salesforce. * **No live agent handoff.** Unlike the [ServiceNow integration](/sections/integrations/servicenow), there is no bridge to a human Salesforce agent chat. * **Single Case treatment.** All Cases are synced the same way regardless of record type - there is no per-record-type configuration. * **Email-to-Case conversations don't sync.** Serval syncs the CaseComment thread. Orgs whose case conversations live in EmailMessage records (typical with Email-to-Case) will see only CaseComment traffic sync - the email thread itself stays in Salesforce. ## Get your credentials To connect Salesforce, you create an app in your Salesforce org (a Connected App, or the newer External Client App) configured for OAuth with the Client Credentials Flow enabled and a Run As user assigned. From it you collect the Consumer Key (your Client ID) and Consumer Secret (your Client Secret), plus your org's instance domain. The full provider walkthrough lives in [Salesforce's Client Credentials Flow setup guide](https://help.salesforce.com/s/articleView?id=sf.connected_app_client_credentials_setup.htm\&language=en_US\&type=5). In Salesforce, go to **Setup**. In the left sidebar under **Platform Tools**, navigate to **Apps → External Client Apps → External Client App Manager**. (Connected Apps work the same way via **App Manager**.) Click **New External Client App** in the top right. Enter a name (for example, "Serval Integration") and fill out the required fields. In the **API (Enable OAuth Settings)** section, enable OAuth. Provide a callback URL - it is not used by this flow, but Salesforce requires a value, so something like `https://serval.com` is fine. Then move the OAuth scopes your workflows need into **Selected OAuth Scopes**. Choose scopes that cover the Salesforce objects your workflows will read or change. You can update scopes later. Under **Flow Enablement**, toggle **Enable Client Credentials Flow** on. This toggle is required. If the Client Credentials Flow is not enabled, Serval cannot authenticate and the connection test will fail. In the app's OAuth / Client Credentials policies, assign a **Run As** user for the Client Credentials Flow. Every Serval API call runs as this user, with this user's object and field permissions. Pick a user whose access matches exactly what your workflows should be allowed to do. If you plan to use ticket sync, also grant this user the object permissions listed in [Required Salesforce permissions](#required-salesforce-permissions). Save the app, then open its OAuth settings and click **Consumer Key and Secret** (you may be prompted to re-verify your identity). The **Consumer Key** is your **Client ID** and the **Consumer Secret** is your **Client Secret**. Record your instance domain (for example, `mycompany.my.salesforce.com`), entered without the `https://` prefix. ## Connect in Serval In Serval, go to **Integrations → All integrations → Salesforce → Connect** and fill in the following fields. All three are required, and Serval will not let you save until each one is filled in. Enter your Salesforce instance domain without the `https://` prefix (for example, `mycompany.my.salesforce.com`). Serval checks that this looks like a valid Salesforce domain - it must end in `.salesforce.com`. If it doesn't match that shape, the form rejects it when you try to save with the message "Must be a valid Salesforce domain (e.g., mycompany.my.salesforce.com)". A well-formed but incorrect domain (the right shape but the wrong org) is accepted, and surfaces later as a failed connection test, so double-check it carefully. Enter the Consumer Key from your Salesforce app. Enter the Consumer Secret from your Salesforce app. When you reconfigure an existing connection later, the saved Client Secret is shown obfuscated, so the real value is never displayed again. Leave it as-is to keep the value you already saved, or click **Replace** to enter a new one. Click **Save** to create the connection. ## Verifying the connection Serval includes a built-in **Test Salesforce Connection** healthcheck. It makes an authenticated request to your org, treats the response as a list of available API versions, and reports the count. This confirms that your instance domain, Client ID, and Client Secret all work together to authenticate against the org. On success, you will see: > Successfully connected to Salesforce. \ API versions available. On failure, you will see: > Unable to connect to Salesforce. Please verify your instance domain, client ID, and client secret are valid. A successful save only confirms the fields were well-formed, not that the credentials actually work. Always run the connection test after connecting to confirm Serval can authenticate to your org. ## Gotchas and troubleshooting The form confirms your **Instance Domain** has a valid Salesforce shape, but it cannot tell whether it points at the right org - a well-formed domain for the wrong org saves cleanly and only fails when Serval tries to authenticate. Re-check the domain (entered without `https://`, e.g. `mycompany.my.salesforce.com`), then re-run the test. If the domain is correct, confirm the Client ID and Client Secret are the Consumer Key and Consumer Secret from the same app. Serval uses the OAuth Client Credentials Flow, so your Salesforce app must have **Enable Client Credentials Flow** turned on and a **Run As** user assigned. If the flow is not enabled, the token request fails and the connection test returns its failure message. Open the app's settings, confirm the flow is enabled, and confirm a Run As user is configured. Every Serval API call runs as the **Run As** user assigned on the app. That user's profile and permission sets determine which objects and fields your workflows can read or write. If a workflow is blocked from a record or field, adjust the Run As user's permissions in Salesforce to match what your workflows need. This integration ships exactly one data action - the generic **Salesforce API request**. There are no separate "create contact" or "query case" actions. Workflows specify the operation and target themselves, so refer to the [Salesforce REST API Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_rest.htm) for what is available. For security, Serval only allows the connected integration to make outbound calls to Salesforce hosts - domains ending in `salesforce.com` or `force.com` (the `force.com` range covers Experience Cloud, community, and custom domains). Any other host is blocked. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Salesforce integration. # Sana Source: https://docs.serval.com/sections/integrations/sana Connect Sana, the AI knowledge and learning platform, to Serval with an API client so workflows can manage users, groups, programs, courses, assignments, teamspaces, and reporting. Currently in beta. ## About Sana Sana is an AI knowledge and learning platform. Serval connects to your Sana tenant using an API client (a client ID and secret) that you create inside Sana, plus your tenant domain (for example `acme.sana.ai`). Once connected, workflows can read and act on your learning data: people, the groups they belong to, the courses and programs they're enrolled in, and the reports that track completion. The Sana integration is currently in **beta**. When you connect, you choose whether Serval has **read** access or **read and write** access. Read access covers everything that looks up or reports on Sana data. Read and write access is required for anything that changes Sana, such as creating a user, enrolling someone in a program, or marking a course complete. Pick read only if you want to be certain that no workflow can ever modify Sana. **Authentication** Serval authenticates with a Sana API client: a client ID and a client secret created in Sana. Serval stores the secret encrypted and exchanges it for a short-lived access token each time it calls Sana, so the workflows you build never handle the secret directly and there is no long-lived token sitting in a workflow. Tokens are refreshed automatically before they expire. **Data sync** On demand only. Serval calls Sana at the moment a workflow step runs. There is no background sync, and the integration ships no pre-installed workflows. ## What the Sana integration enables Workflows can work with the main areas of your Sana tenant: | Capability | Description | | - | - | | Users | Look up and manage people in Sana: create, update, and remove users, send or regenerate invitations, set a user's manager, and read the groups a user belongs to. | | Groups | Manage groups and their membership: create, update, and delete groups, add or remove members, and change a member's role. Groups are how course and program assignment is often organized. | | Programs | Manage structured learning programs: create, update, and delete them, and enroll or unenroll members. | | Courses | Manage courses: create and link courses, update them, and record progress such as marking a course completed or resetting it for a learner. | | Assignments | See what content is assigned to a person, and assign or unassign content to them. | | Paths | Read the learning paths defined in your tenant. | | Teamspaces | Manage teamspaces and their membership: create and delete teamspaces, and add or remove members. | | Reporting | Run reporting jobs to pull completion and engagement data out of Sana for use in the rest of Serval. | Serval works with your tenant's learning and knowledge data. It doesn't configure single sign-on or identity-provider user provisioning for Sana, which are set up directly in your identity provider. ## Get your credentials You create an API client inside Sana and give Serval its client ID and secret. The API client's access in Sana determines what Serval can do, so create it with the scopes your workflows need. Sign in to your Sana tenant with an account that can manage API clients. Go to **Manage → API** in Sana and create a new API client. Grant it read access, or read and write access, to match how you plan to use it in Serval. Copy the client ID and client secret. Store the secret somewhere safe: you will paste it into Serval, and Sana may show it only once. Your tenant domain is the host you use to reach Sana, for example `acme.sana.ai`. You will enter this in Serval. Serval only connects to hosts under `sana.ai`. Enter your real tenant host (for example `acme.sana.ai`), not `sana.com`, which belongs to an unrelated company. ## Connect in Serval Open your team workspace, go to **Integrations → Connect new**, choose **Sana**, and fill in the connect form. Every field is required. Enter your tenant host without `https://`, for example `acme.sana.ai`. Serval tidies up a pasted address (it strips the scheme, any trailing slash, and any path). Paste the client ID from the API client you created in Sana. Paste the client secret. Serval stores it encrypted and only ever uses it to mint the short-lived tokens it needs to call Sana. Choose **Read and write** (the default) or **Read only**. Write access is required for any workflow that changes Sana. Choose read only to guarantee that workflows can never modify your Sana data. Submit to create the connection. Serval verifies it with a health check against your tenant. ## Verifying the connection When you connect, Serval runs a check that confirms it can mint a token from your credentials and reach your tenant. The integration also includes four built-in health checks you can run at any time from the connection's **API Integration** tab: | Check | What it verifies | | - | - | | Test Connection | Confirms Serval can obtain a token from your client credentials and reach the tenant API. | | List Users | Confirms read access to user records. | | List Groups | Confirms read access to groups. | | List Courses | Confirms read access to courses. | If every check fails with valid-looking credentials, the most common cause is that the API client in Sana wasn't granted the access you chose in the connect form. Confirm the client's scopes in Sana, then rerun the checks. ## Gotchas and troubleshooting The access you pick at connect time is enforced on every call. A connection created with read only can't create users, enroll people, or mark courses complete, even if a workflow asks it to. If a write action fails, check whether the connection (and the underlying Sana API client) has write access. Serval only reaches hosts under `sana.ai`, and the host you enter is where every request goes. Enter your tenant host (for example `acme.sana.ai`) without `https://`. Don't use `sana.com`, which belongs to an unrelated company. Serval can do exactly what the API client is allowed to do in Sana. If workflows hit permission errors while the connection looks healthy, widen the client's access in Sana (or create a new client with the scopes you need) and update the connection. The Sana integration is marked beta in the connect screen. Behavior and available capabilities may change. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Sana integration. # SAP Concur Source: https://docs.serval.com/sections/integrations/sap-concur Connect SAP Concur, the travel and expense management platform, so Serval workflows can read and manage expense reports, travel requests, invoices, vendors, and users on demand. ## About SAP Concur SAP Concur is a travel, expense, and invoice management platform. Serval's Concur integration connects to your company's Concur tenant with a company-level OAuth connection and calls the Concur APIs on demand from workflow steps - there are no background jobs or scheduled imports. **Authentication:** Company-level OAuth 2.0. An administrator generates a one-time **company request token** in the Concur admin console; Serval exchanges it once for long-lived OAuth tokens and refreshes them automatically from then on. No individual user signs in, so the connection is unaffected by SSO or MFA and does not depend on any one admin's account. **Data sync:** On demand only. Serval contacts your Concur data center exclusively when a workflow step or health check runs. ## What the SAP Concur integration enables | Capability | Description | | - | - | | Expense | List, read, create, and update expense reports, entries, itemizations, allocations, attendees, and receipt images. | | Travel requests | List, read, create, update, and action travel requests, including their expected expenses, cash advances, comments, and exceptions (v4 Request API). | | Invoice | Work with payment requests (invoices), purchase orders and their receipts, vendors, vendor banks, and vendor groups. | | Configuration data | Read and manage lists and list items (v4 List API, including bulk operations), and read expense group configurations and attendee types. | | Users and identity | Read and manage users through the v4 SCIM Identity API. | Anything defined in the [SAP Concur APIs](https://developer.concur.com/api-reference/) v3.0/v3.1 Web Services, the v4 Request and List APIs, and the v4 SCIM Identity API can be accessed through Serval, subject to the scopes granted to your Concur application. Serval deliberately ships no deprecated Concur endpoints - superseded v3 APIs (Requests, Users, Lists, Locations) are covered by their v4 successors instead. ## Get your credentials You need four values from Concur: your **geolocation** (API data-center hostname), a **Client ID** and **Client Secret** from a Concur OAuth application, and your **Company UUID** plus a **company request token** generated by an administrator. Concur's [authentication guide](https://developer.concur.com/api-reference/authentication/getting-started.html) covers the flow in detail; SAP also publishes a [step-by-step tutorial](https://developers.sap.com/tutorials/data-to-value-conn-concur-part01..html) that walks through the same screens. Open your SAP Concur admin panel and sign in with an administrator account. Go to the **OAuth 2.0 Application Management** screen and click **Create New App**. Fill in the required fields and add the grants and scopes your workflows will need. Submit, then copy the generated **Client ID** and **Client Secret** somewhere safe. Go to the **Company Request Token** screen, enter your application's **App ID**, and click **Submit**. Concur shows your **Company UUID** and a **company request token** - copy both immediately. This is the API hostname for the data center that hosts your company, for example `us.api.concursolutions.com` (US) or `eu.api.concursolutions.com` (EU). If you are unsure, your Concur administrator or SAP contact can confirm it. The company request token expires **24 hours** after it is generated and is consumed on first use. Generate it right before you connect in Serval; if it expires first, simply generate a new one from the same screen. Grant the application the identity read scopes (for the v4 Identity API) and expense read scopes so Serval's connection health checks can pass, plus whatever additional scopes your workflows need. If your application cannot generate a company request token, ask SAP Concur support to enable the company-level (request token) grant for it. ## Connect in Serval In Serval, add a new connection and choose **SAP Concur**. The API hostname for your data center, matching the placeholder `us.api.concursolutions.com`. You can paste either the bare hostname or a full URL - Serval strips the scheme and any path for you. The value must be a `concursolutions.com` hostname; anything else fails with "Geolocation must be a SAP Concur data center host". The OAuth2 credentials from your Concur application. The secret is entered in a password field; when you reopen the form later it appears masked, with a control to replace it. The Company UUID shown alongside the request token in the Concur admin console. The company request token generated in the previous section. It is required when first connecting (and when re-authenticating later); it is used exactly once, to obtain Serval's long-lived OAuth tokens, and is never stored. Serval immediately exchanges the request token with Concur when you save. If anything is wrong you get an error at this point: "Could not authenticate with SAP Concur. Verify the geolocation, Client ID, Client Secret, Company UUID, and request token (request tokens expire 24 hours after they are generated)." When editing an existing connection, leave the **Request Token** field blank to keep the current tokens - it is only needed again if you re-authenticate. Changing the **Geolocation**, **Client ID**, or **Company UUID** requires a fresh request token, because the stored tokens are bound to those values; saving such a change without one fails with "Request Token is required to change the geolocation, Client ID, or Company UUID." ## Verifying the connection The SAP Concur integration ships three health checks. Run them right after connecting. **Test Concur Connection** - authenticates and calls the v4 Identity API. This check is license-agnostic, so it passes regardless of which Concur modules (Expense, Travel, Invoice) your tenant licenses. * Success: "Successfully authenticated with SAP Concur" * Failure: "Unable to connect to SAP Concur. Verify the geolocation, Client ID, Client Secret, Company UUID, and request token are correct." **List Expense Reports** - lists recent expense reports through the v3 Expense API to verify read access. * Success: "Successfully retrieved expense reports from SAP Concur" * Failure: "Unable to list expense reports from SAP Concur." **List Users** - lists a page of users from the v4 Identity API to verify directory read access. * Success: "Successfully retrieved users from SAP Concur" * Failure: "Unable to list users from SAP Concur." A mix of green and red checks usually means missing scopes or an unlicensed module, not a broken connection. The identity checks need the application's identity read scopes; the expense check needs expense read scopes and an Expense-licensed tenant. Add the missing scope to the application in Concur - scope changes may require a re-authentication with a fresh request token. ## Gotchas and troubleshooting Concur request tokens are valid for 24 hours and are consumed when Serval exchanges them. This is normal: after connecting, Serval holds an access token (about one hour) and a refresh token (about six months) and rotates them automatically. You only need a new request token to re-authenticate - for example after changing identity fields or if the connection is unused for longer than the refresh token's lifetime. Concur refresh tokens last about six months. If the integration makes no Concur calls for longer than that, the stored tokens expire and workflows fail until you re-authenticate: generate a new company request token in Concur and enter it in the connection settings. Access is exactly the grants and scopes on your Concur OAuth application. If a workflow gets permission errors from Concur, add the scope to the application in the OAuth 2.0 Application Management screen, then re-authenticate with a fresh request token so the new scopes take effect. Every Concur company is assigned to a data center, and API calls must go to that host. Serval stores the geolocation Concur itself reports when the connection is created, so calls are routed correctly even if you entered a more generic host. If your company is migrated to a different data center, update the connection (with a fresh request token). Serval attaches OAuth credentials and tokens exclusively to requests bound for `*.concursolutions.com` hosts. Requests to any other destination never receive the credential, and the connection form rejects non-Concur hostnames outright. Concur v3 list results are paginated with a limit and a next-page link. A single workflow step returns only one page, so workflows that need everything must loop until there are no more pages. If a workflow seems to be "missing" records, pagination is the usual cause. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your SAP Concur integration. # SAP LeanIX Source: https://docs.serval.com/sections/integrations/sap-leanix Connect Serval to SAP LeanIX so workflows can read and update the enterprise architecture inventory — fact sheets, relations, the meta model, and GraphQL. ## About SAP LeanIX SAP LeanIX is an enterprise architecture management platform. Its inventory of **fact sheets** — applications, IT components, business capabilities, providers, projects and their relations — is often the system of record for what software an organization runs and who owns it. The Serval SAP LeanIX integration connects to your workspace through the **Pathfinder** API. Workflows can read and update fact sheets, traverse relations, inspect the workspace data model, and run arbitrary GraphQL queries. The integration is marked **Beta** in Serval's connect UI. **Authentication:** OAuth 2.0 client credentials. Serval exchanges your API token for a short-lived bearer token at `https://{instance}.leanix.net/services/mtm/v1/oauth2/token` and attaches it to API requests at `https://{instance}.leanix.net/services/pathfinder/v1`. **Data sync:** On demand only. There is no background inventory sync. ## What the SAP LeanIX integration enables | Capability | Description | | - | - | | SAP LeanIX API request | Typed access to the full Pathfinder v1 surface — fact sheets, relations, bookmarks, exports, the meta model, and workspace settings. | | SAP LeanIX GraphQL request | Runs GraphQL queries and mutations, the only LeanIX surface that filters, sorts and pages fact sheets on arbitrary fields. GraphQL-level errors are raised rather than silently returned. | | Pathfinder API discovery | The full Pathfinder endpoint catalog is indexed for workflow authoring. | LeanIX answers a failed GraphQL operation with HTTP 200 and an `errors` array. The GraphQL action raises those as errors so a broken query fails the workflow step instead of returning an empty result. ## Get your credentials You need your **instance host**, your **workspace name**, and an **API token** for a technical user in that workspace. Sign in to LeanIX and read both out of the browser URL. In `https://us-2.leanix.net/acme/dashboard` the host is `us-2.leanix.net` and the workspace is `acme`. The host is region-specific (`us-2`, `eu-1`, `app`, `demo-eu-1`, …) and determines both the API endpoint and the token endpoint. Go to **Administration → Technical Users** and create a technical user for Serval, scoped to the workspace you want to connect. Grant at least **MEMBER** to read fact sheets. Writing fact sheets needs a role with write permission; reading the meta model and workspace settings needs **ADMIN**. Copy the generated API token. LeanIX shows it once — store it before closing the dialog. An API token inherits its technical user's permission role for the whole workspace. Give the Serval technical user the lowest role that covers your workflows, and use a separate technical user per environment rather than sharing one token. ## Connect in Serval In Serval, add the SAP LeanIX integration. It is labeled **Beta**. Enter the host, such as `us-2.leanix.net`. Pasting the full workspace URL is fine — the scheme and path are stripped. Enter the workspace name, such as `acme`. Several workspaces can share one regional host, so this is what identifies the workspace this connection points at. Paste the technical user's API token in the password field. Submit the form. Serval runs four health checks (below). When editing an existing connection, a blank or obfuscated API token keeps the stored value. Paste a new token to rotate credentials without re-entering the instance host. ## Verifying the connection Four health checks run after you connect: 1. **Test SAP LeanIX Connection** — exchanges the API token and reads the workspace data model. Success reports how many fact sheet types the workspace defines. 2. **List SAP LeanIX Fact Sheets** — reads one fact sheet and reports the workspace total. Confirms inventory read access. 3. **Run SAP LeanIX GraphQL Query** — runs `{ allFactSheets(first: 1) { totalCount } }`. Confirms the GraphQL endpoint accepts queries from this integration. 4. **Read SAP LeanIX Workspace Settings** — confirms the elevated permissions that workspace-level reads require. If the first three checks pass but workspace settings fails, the technical user authenticates and can read the inventory but is below **ADMIN**. That is a valid setup for read-only inventory workflows. ## Gotchas and troubleshooting LeanIX API tokens are scoped to a single workspace. To reach several workspaces, connect SAP LeanIX once per workspace — each connection carries its own host, workspace and token. Two connections on the same host must name different workspaces; Serval identifies a connection by host and workspace together. A token issued on `eu-1.leanix.net` will not authenticate against `us-2.leanix.net`. A 401 immediately after connecting usually means the host and the token belong to different regions. `GET /factSheets` only narrows by fact sheet type. Filtering by name, tag, subscription, lifecycle or any custom field — and sorting or paging on them — is only available through GraphQL. Creating or updating a fact sheet must satisfy the workspace's data model, including required fields and permitted relation types. LeanIX rejects violations with HTTP 422 and a validation payload rather than partially applying the change. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your SAP LeanIX integration. # SAP SuccessFactors Source: https://docs.serval.com/sections/integrations/sap-successfactors Connect Serval to SAP SuccessFactors to read and write HR data - users, employment records, org structure, time off, performance, recruiting, and onboarding - from workflows. ## About SAP SuccessFactors SAP SuccessFactors is SAP's cloud HCM suite - core HR (Employee Central), performance and goals, recruiting, onboarding, and time management. Serval connects to one SuccessFactors tenant per connection - the connection is named "SAP SuccessFactors \[Company ID]" - and calls the tenant's OData V2 APIs on demand when your workflows run. **Authentication:** OAuth 2.0 with SAML 2.0 bearer assertions - the only method SAP supports for new integrations (HTTP Basic Auth retires in November 2026). Serval signs a short-lived SAML assertion with a private key whose X.509 certificate is registered on an OAuth client in your tenant, exchanges it for a bearer token, and refreshes automatically. Serval can generate the key pair for you, so the private key never leaves Serval and you only ever handle the public certificate - SAP's recommended setup. **Data sync:** On demand only. SuccessFactors data is read or written when a workflow step runs - there is no background sync or entity ingestion. ## What the SuccessFactors integration enables | Capability | Description | | - | - | | Users and employee data | Read and update user accounts, personal information, and employment records (User, PerPerson, EmpJob, and related entities). | | Organization structure | Read Foundation Objects - departments, divisions, locations, cost centers. | | Time off | Read and manage absences, balances, and time types (Employee Central Time Off). | | Performance and goals | Goal plans, continuous performance activities, review forms, feedback, and 360 reviews. | | Recruiting | Candidates, job requisitions, applications, offers, and interviews. | | Onboarding | Current-generation Onboarding (OBX) processes and tasks. | | Connection health checks | Built-in checks verify authentication, user listing, and - where Employee Central is licensed - person and org-structure reads. | Serval exposes one typed API request action per module, all calling the tenant's `/odata/v2` root. Entities from modules your tenant doesn't license return permission errors - that's expected and doesn't indicate a broken connection. ## Permissions model SuccessFactors OAuth tokens carry no scopes. What a connection can access is controlled entirely by the **role-based permissions (RBP)** of the API user you name in the connection. Create a dedicated API user and grant it a permission role with exactly the OData entity access your workflows need. ## Before you start You need: * Admin access to your SuccessFactors tenant with the **Manage Integration Tools → Manage OAuth2 Client Applications** permission. * Your tenant's **API server** and **company ID**. Both are visible to admins in **Admin Center → API Center**; the company ID is also shown in the upper-right corner of Admin Center. The API server is data-center specific (for example `api4.successfactors.com`) - if you're unsure, ask whoever administers your tenant, or see SAP's [List of SAP SuccessFactors API Servers](https://help.sap.com/docs/successfactors-platform/sap-successfactors-api-reference-guide-odata-v2/list-of-sap-successfactors-api-servers). ## Step 1 - Create a dedicated API user Create a user such as `sfapi.serval`. A dedicated user keeps the connection's access auditable and independent of any employee's account. In **Admin Center → Manage Permission Roles**, create a role for the integration and assign it to the API user (via a permission group). Grant the OData API access your workflows need - typically **User Search** under General User Permission, plus the **Employee Central API** permissions (effective-dated entities) if you use Employee Central, and module permissions for anything else your workflows touch (Recruiting, Time Off, and so on). Grant the minimum entity access your workflows need. The API user's role is the connection's entire authorization surface - there are no OAuth scopes to narrow it further. ## Step 2 - Register the OAuth client and connect In Serval, open the SAP SuccessFactors integration and choose **Connect**. Fill in the API server and company ID, then: With **Certificate** set to "Generate a certificate for me", choose **Generate certificate**. Serval creates the key pair, shows the public certificate, and keeps the private key - it is never displayed and never leaves Serval. In **Admin Center → API Center → OAuth Configuration for OData**, choose **Register Client Application**. Enter an application name (for example "Serval") and application URL (identification only), and paste the certificate from Serval into the **X.509 Certificate** field. Save the registration. Choose **View** on the registered application and copy its **API key** into Serval's **Client ID (API key)** field. Enter the API user ID from step 1 and submit. Serval runs health checks automatically. Register a client application as above, pasting your certificate's base64 body into the **X.509 Certificate** field - enter only the body, without the BEGIN and END lines, or SuccessFactors rejects it. In Serval, set **Certificate** to "Paste my own private key" and paste the RSA private key that matches the registered certificate, including the BEGIN and END lines. Copy the application's **API key** into the Client ID field, enter the API user ID, and submit. Consider enabling Bind to Users on the OAuth client and binding it to your API user, so only that user can request tokens for this client. Also note: changing or regenerating the certificate on a registered client invalidates the existing configuration - rotate by updating both sides together. ## Troubleshooting | Symptom | Likely cause | | - | - | | Health check fails with a 401 or invalid\_grant | The certificate registered on the OAuth client doesn't match the private key, or the client ID / company ID / API user ID doesn't match the tenant. | | Worked before, now 401s | The certificate was regenerated or replaced on one side only - re-register the current certificate, or generate a new one in Serval and update the client registration. | | User reads work but Employee Central entities fail | The tenant doesn't use Employee Central, or the API user's role lacks Employee Central OData permissions. | | A module's endpoints return 403 or "no permission" | The module isn't licensed on the tenant, or the API user's role-based permissions don't cover those entities. | # Saviynt Source: https://docs.serval.com/sections/integrations/saviynt Connect Serval to Saviynt Enterprise Identity Cloud so workflows can query users, applications, roles, and access-request data through the EIC REST API. ## About Saviynt Saviynt Enterprise Identity Cloud (EIC) is an identity governance and administration platform. The Serval Saviynt integration connects to your EIC tenant with an admin username and password. Serval exchanges those credentials for short-lived bearer tokens via `/ECM/api/login` and attaches them to every proxied request — workflow code never sees the password. The integration is marked **Beta** in Serval's connect UI. **Authentication:** Username and password → bearer token exchange. Tokens are cached until five minutes before expiry, then refreshed automatically. **Data sync:** On demand only. There is no background sync of Saviynt users, roles, or entitlements. ## What the Saviynt integration enables | Capability | Description | | - | - | | Saviynt API request | Typed access to the Saviynt EIC Chicago REST API — users, accounts, entitlements, roles, SAV roles, endpoints (applications), security systems, access requests, certifications, and other `/ECM/` and `/ECMv6/` operations your admin account can reach. | | Read-oriented health checks | Connection tests exercise authentication, application (endpoint) listing, user listing, and SAV role listing. | Most Saviynt list operations are **POST** requests with JSON filter bodies rather than GET queries — prebuilt and custom workflows should follow the typed method for each path. ## Get your credentials You need your EIC instance hostname and an admin account Serval can use for API login. Your Saviynt EIC host typically looks like `company.saviyntcloud.com`. Copy the hostname without `https://`. Use a Saviynt admin user whose roles cover the data and mutations your workflows will perform. The account's Saviynt roles govern every API call. Serval stores the password encrypted and uses it only inside the proxy to call `/ECM/api/login`. Saviynt API documentation for the Chicago release is available in Saviynt's [Postman collection](https://documenter.getpostman.com/view/50568759/2sB3dMyrnT). ## Connect in Serval In Serval, add the Saviynt integration. It is labeled **Beta**. Enter your EIC tenant host without `https://` (for example `company.saviyntcloud.com`). Serval strips schemes, trailing slashes, and paths if you paste a full browser URL. Enter the Saviynt admin username used for `/ECM/api/login`. Enter the admin password in the password field. Submit the form. Serval runs four health checks (below). When editing an existing connection, leave the password as its obfuscated placeholder to keep the stored credential, or paste a new password to rotate. ## Verifying the connection Four health checks run after you connect: 1. **Test Connection** — calls `GET /ECM/api/v5/getSecuritySystems` after login. Success: `Successfully connected to Saviynt.` Auth failure: `Authentication failed. Verify your Saviynt instance URL, username, and password.` 2. **List Applications** — POST to `/ECM/api/v5/getEndpoints` (Saviynt models applications as endpoints). Confirms endpoint read access. 3. **List Users** — GET `/ECM/api/v5/user`. Confirms user read access. 4. **List SAV Roles** — GET `/ECM/api/v5/getSavRoles`. Confirms role read access. If authentication succeeds but application or user checks fail, the admin account can log in but lacks read permissions for that resource type in Saviynt. Adjust the account's Saviynt admin roles. ## Gotchas and troubleshooting Endpoints like `getEndpoints`, `getPendingRequests`, and many search operations expect a JSON body with filters and pagination. Check the typed schema for each path before authoring workflows. Paste `company.saviyntcloud.com`, not a path under `/ECM/`. Serval builds login and API URLs from the normalized host. Saviynt enforces authorization on the admin account you configure. A workflow that succeeds in dev against a sandbox admin may fail in prod if the production account lacks write privileges. When you update the username or password in Serval, cached bearer tokens for the old credentials are discarded automatically. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Saviynt integration. # ScreenMeet Source: https://docs.serval.com/sections/integrations/screenmeet Connect ScreenMeet to Serval to inspect remote support and screen-sharing sessions from your workflows. ## About ScreenMeet ScreenMeet is a remote support and screen-sharing platform that lets IT and support teams join end-user sessions for troubleshooting, cobrowsing, and live assistance. Connecting ScreenMeet to Serval enables workflows that look up support sessions, correlate them with help desk tickets, and audit session activity from your service desk. This integration is currently in **beta**. The shipped installable workflows focus on reading session data; additional ScreenMeet API capabilities may be added over time. ## What the ScreenMeet integration enables | Capability | Description | | - | - | | List sessions | List organization support sessions with optional filters for state, session type, pagination, and unattended-only sessions | | Get session | Retrieve details for a single session by ID, including state, agent/user URLs, and scheduling metadata | | CRM lookup | List sessions linked to an external CRM object mapping key (for example, a help desk ticket or case record) | | Custom workflows | Build additional workflows against any endpoint in the [ScreenMeet v3 API](https://developer.screenmeet.com/docs/screenmeet/asxx9zjzbp1qo-api-overview) | The SDK also exposes create and close session endpoints, but the installable workflows shipped with this integration are read-focused. *** ## ScreenMeet configuration ### Prerequisites Before connecting ScreenMeet in Serval, ensure you have: * Administrator access to **ScreenMeet Console** * Permission to create **API keys** for your organization Serval authenticates with ScreenMeet using OAuth 2.0 **client credentials** (server-to-server). It exchanges your Client ID and Client Secret for a short-lived bearer token at `https://app.screenmeet.com/v3/oauth/token`, then sends that token in the `Authorization: Bearer` header on each API request. You do not configure a static bearer token or redirect URL. ### Create API credentials 1. Log in to **ScreenMeet Console** as an administrator 2. Go to **Organization** → **API Keys** 3. Create a new API key 4. Copy the credentials shown after creation: * **Client ID**: Your application's unique identifier * **Client Secret**: Your application's secret key The Client Secret is shown only once when the key is created. Store it securely. If you lose it, create a new API key in ScreenMeet Console. *** ## Serval configuration 1. In Serval, go to **Integrations → All integrations → ScreenMeet → Connect** 2. Enter the following information: | Field | Description | | - | - | | Instance Name | A friendly name for this ScreenMeet integration instance | | Client ID | The Client ID from ScreenMeet Console API keys | | Client Secret | The Client Secret from ScreenMeet Console API keys | 3. Click **Save** Serval verifies the connection by fetching your authenticated ScreenMeet user account. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your ScreenMeet integration. # ServiceNow Source: https://docs.serval.com/sections/integrations/servicenow Connect ServiceNow to Serval with OAuth 2.0 client credentials or Basic authentication for bidirectional ticket sync, catalog import, knowledge sync, access profiles, and optional live agent handoff. ## About ServiceNow ServiceNow is an IT service management (ITSM) platform that manages tickets, incidents, change requests, problems, and the service catalog. Connecting ServiceNow to Serval enables native bidirectional ticket sync, service-catalog import and ordering, knowledge-base sync (with optional mirroring of articles into Serval's native knowledge base), and workflow automation across incidents, problems, changes, and HR cases. Each connection uses either OAuth 2.0 (client credentials) - the default and recommended option - or HTTP Basic authentication, and acts as a dedicated integration service account in your ServiceNow instance. **Authentication:** OAuth 2.0 (client credentials), or Basic auth **Data sync:** Bidirectional. Serval polls ServiceNow for ticket and comment updates (with an optional Business Rule webhook for near-real-time comment sync), keeps groups, roles, departments, companies, locations, and cost centers current with scheduled background syncs, can mirror synced knowledge articles into a read-only native Serval knowledge base, and writes back via the Table, Service Catalog, and Change Management REST APIs on demand when workflows run. Sync frequency is admin-configurable per sync. ## What the ServiceNow integration enables | Capability | Description | | - | - | | Ticket sync | Native bidirectional sync between Serval tickets and ServiceNow incidents, catalog requested items, and HR cases - including comments and work notes. ServiceNow incidents are created in Serval as incident tickets with incident statuses; requested items and HR cases are created as requests. When a requested item syncs in, its first Serval ticket message also lists the requester's answers to the catalog item's questions. | | Service catalog import | Import ServiceNow catalog items so employees can order them through Serval - as a confirmed form, a pure conversation, or a link back to ServiceNow - with reference data, access rules, and source-system popularity carried over. | | Improve with Catalyst | Hand any imported catalog item to Catalyst, which redesigns the ITSM form as a conversational Serval experience and submits the request back to ServiceNow. | | Knowledge base | Sync ServiceNow knowledge articles into Serval so the AI agent can answer from your documented guidance - and optionally mirror them into a read-only native Serval knowledge base. Accepting a [knowledge suggestion](/sections/documentation/suggestions/overview) also creates (as draft) or updates articles in ServiceNow. | | Workflow automation | Build workflows that create and update incidents, problems, and change requests, including approvals and HR cases. | | Access profiles and resource sync | Sync ServiceNow groups, roles, departments, companies, locations, and cost centers, and provision or deprovision group and role membership for access control. | | User criteria import | Import ServiceNow user criteria as Serval access profiles so the same people who can request an item in ServiceNow can request it in Serval. | | Configurable sync settings | Set per-sync frequency (hourly through weekly, or automatic) and an optional ServiceNow encoded-query filter that scopes which catalog items are imported. | | Real-time comment sync (optional) | A single ServiceNow Business Rule pushes new comments to Serval for near-instant delivery instead of waiting for the next poll. | | Live agent handoff (optional) | Hand a conversation off to a human ServiceNow agent through Virtual Agent Bot-to-Bot and bridge the agent's replies back into the Serval ticket. | Anything exposed by ServiceNow's REST APIs can be accessed through Serval (see the [ServiceNow product documentation](https://www.servicenow.com/docs/)). ### Catalog import Each catalog item is imported in one of three modes, chosen with the **Collect inputs as** control (and the split Import button) on the catalog import page: | Mode | What the employee experiences | | - | - | | **Form** | "The agent shows a form to confirm the fields before submitting." | | **Chat** | "The agent gathers what's needed conversationally, then submits - no form." | | **Link** | "The agent sends a link to complete the request in the external system." | Items Serval cannot faithfully render fall back to link-only automatically, with the reason shown - client scripts, scripted UI policies, UI scripts, unsupported required field types, or dynamic JavaScript reference qualifiers. Per-item controls let you toggle form confirmation (Form vs. Chat), set **Force link-only mode** (always redirect employees to the ServiceNow form), unimport, or disable an item. ServiceNow record producers are submitted through the producer API and return a direct link to the record they create. Serval doesn't sync that record with the intake ticket, so completing the intake can't change the produced record's assignment group or status. Unlike a regular catalog item, a record producer has no guaranteed requester field, so Serval sets the requester on a best-effort basis. When an employee places the order, Serval writes the ordering employee to the first of **Requested for**, **Requested by**, **Opened for**, or **Caller** that the produced record accepts. If none of those fields can be written, the record keeps the Serval integration service account as its requester and the submission still succeeds. When an employee orders an imported catalog item through Serval, the ServiceNow request's **Requested for** is set to that employee, so the order is attributed to the person it's for rather than to the Serval integration service account. Forms with reference fields - lookups into ServiceNow tables - prompt a **Set up reference data** step. Confirming **Set up reference data** creates entity ingestion configs for those tables so pickers resolve real options; use **Re-sync** to refresh them later. Until reference data is set up, the item shows a **Reference data not set up** state. While browsing, catalog items appear as structured cards with field counts and a **Ready** status, a category filter, and a **Most requested** sort backed by source-system popularity ("Ordered N times in the source system"). Each item's **Understanding** tab shows everything Serval captured from ServiceNow - variables, client scripts, UI policies (rendered as When/Show/Hide/Require/Lock rules, with scripted ones flagged), script includes, and the user criteria that gate access - along with an AI second opinion on whether the item can be filled conversationally. If a sync gets stuck, it can be cancelled or restarted with **Sync now**; stale syncs are detected automatically. ### Improve with Catalyst Every imported catalog item has an **Improve with Catalyst** action. It launches a Catalyst session pre-loaded with the item's full captured understanding - variables, client scripts, UI policies, script includes, user criteria, and the imported workflow as a starting point - plus a built-in skill that reimagines the ITSM form as a conversational Serval experience: one orchestrating skill that asks only what the employee must actually decide, small collection workflows per branch, and a submit workflow that posts the request back to ServiceNow and links the resulting requested item to the ticket. There are two entry points: for natively importable items ("Turn this form into a conversation"), and for items too complex to import, where Catalyst redesigns around the client scripts and UI policies that block native import. Resources Catalyst builds stay attached to the catalog item under a **Built with Catalyst** list (with Skill/Workflow badges and an Unlink action), even after the session ends. This is the recommended path for items that were flagged link-only. ### Importing user criteria as access profiles The **User Criteria** tab in the catalog import area imports ServiceNow user criteria as Serval access profiles. Pick a ServiceNow connection, click **Sync user criteria** to pull criteria from ServiceNow (progress is live-polled, and failures show error details with copyable run identifiers), then review each criterion and choose **Import as access profile**. The detail panel for each criterion shows: * **Who it matches** - groups, roles, user attribute conditions (attribute criteria such as department or location map to Serval access-profile attribute conditions), and individual users. * **What it makes requestable** - the catalog items the criterion gates, including whether each link is an allow ("Available") or deny ("Not available") relationship. * **Proposed access profile** - a preview of the Serval equivalent before you import. Criteria backed by ServiceNow match scripts show a **Cannot be fully mirrored** warning, and a criterion with no captured conditions warns that importing it would grant access to everyone on the team. A bulk **Set up all access profiles** action imports everything outstanding, with progress shown. Each catalog item's Access tab cross-links to the user criteria that gate it and back; once imported, the access profiles gate the corresponding catalog items in Serval the same way ServiceNow does. ### Mirroring knowledge articles into Serval Knowledge sync can do more than index articles for search: once syncing is enabled for a knowledge source, the source's settings panel shows an **Import to Serval Knowledge Base** toggle (off by default). Its help text reads: "When enabled, synced articles from ServiceNow are also written into a Serval native knowledge base. Disable to stop syncing without deleting already-imported pages." When enabled: * Mirrored knowledge bases appear in the Knowledge Bases sidebar under a **From your apps** section. * Mirrored documents are sync-locked and read-only, with a banner - "This document is synced from ServiceNow and is read-only." - and a **View in ServiceNow** link. * Article HTML is converted to native editor blocks (tables, lists, and headings are supported), and the folder hierarchy from ServiceNow is preserved. * Re-syncs update content in place and record version history. * Clicking a knowledge item reference offers a destination choice: **Open in Serval** or **Open in ServiceNow**. Disabling the toggle stops future writes but keeps already-imported pages - they freeze rather than delete. Sources or folders with nothing syncable show a **No documents** sync status. ### Sync settings: frequency and catalog filter A **Sync settings** dialog - reachable from the app instance's Workflow Sync settings and from the catalog import page - exposes two controls for catalog sync: * **Catalog filter** - an optional ServiceNow encoded query (for example `category=hardware^active=true`). Only matching catalog items are imported; leaving it blank imports everything. The filter is combined (AND) with the standard active-items filter. This field appears only for integrations that support it - currently ServiceNow. * **Sync frequency** - Default (30 minutes), Every hour, Every 6 hours, Every 12 hours, Once a day, or Once a week. * **Portal path** - which ServiceNow portal imported catalog items link back to. Choose **Service Portal** (`/sp`, the default) or **Employee Center** (`/esc`), or enter a custom path. Changing it re-syncs the catalog so the links are regenerated; leaving Service Portal selected tracks the integration default rather than pinning a value. This control appears only for integrations that support it - currently ServiceNow. Database/entity ingestion syncs are configurable too: each entity ingestion config's side panel has the same **Sync frequency** selector. Two things to know about cadence: * Unset means the platform default: catalog sync fan-out runs every 30 minutes for ServiceNow, and entity ingestion ticks every 4 hours. * A configured interval is a **floor, not an exact cadence** - scheduled ticks are skipped until the interval has elapsed since the last completed sync. For entity syncs, values at or below 4 hours behave like **Default (4 hours)**; only the 6-hour, 12-hour, daily, and weekly settings genuinely throttle. ### How formatting translates to ServiceNow ServiceNow journal fields (comments and work notes) and description/close-notes fields render plain text only, so everything Serval writes into them is automatically converted from Serval's rich formatting to clean plain text. This applies to the built-in two-way ticket sync for all three ServiceNow ticket types - incidents, catalog requested items, and HR cases - covering ticket descriptions on create and update, and message bodies posted as comments or work notes. | Serval formatting | What ServiceNow receives | | - | - | | Links and images | "text (url)" - ServiceNow auto-linkifies bare URLs | | Bullet and numbered lists | Normalized list lines beginning with "- " | | Bold, italic, headings, code markers | Stripped, text preserved | | @-mentions | Resolved to the user's name | Custom workflows that write their own content into ServiceNow text fields should run it through the markdown-to-ServiceNow-text helper the ServiceNow SDK provides, so raw formatting markers do not leak into the record (see the gotcha below). ### Copying ServiceNow attachments into Serval tickets Custom workflows can move a file attached to a ServiceNow record onto a Serval ticket. Inside a single workflow action, download the attachment's bytes through Serval's integration connection using the SDK's binary request helper, which uses your stored ServiceNow credentials and reads the file as raw bytes, then attach those bytes to the ticket as a message or internal note. Keep the download and the attach in the same action so the file itself never appears in the workflow's run history; only the resulting attachment id does. Serval stores attachments up to 50 MB and refuses executables, installers, and scripts, so read each attachment's size and file name from ServiceNow first and skip files that would be rejected. List a record's attachments with a Table API query on `sys_attachment` filtered by `table_name` and `table_sys_id`, then copy them one at a time so a run that stops part-way resumes without duplicating files. ### Finding the linked record in Serval When a Serval ticket is synced to ServiceNow, its side panel shows a **View in ServiceNow** button with the ServiceNow record number (for example, `INC0010001`) beneath it. This lets an agent confirm at a glance which incident, catalog requested item, or HR case the ticket maps to before opening it. *** ## How the connection works Each ServiceNow connection acts as a dedicated integration user. Your team can connect multiple accounts to the same ServiceNow instance. You pick one of two authentication methods for each connection: * **OAuth 2.0 (Client Credentials)** - the default and recommended option. On each request, Serval exchanges your **Client ID** and **Client Secret** for a short-lived bearer token from your instance's token endpoint (`https://.service-now.com/oauth_token.do`) and sends that token on every API call. ServiceNow runs those calls as the **OAuth Application User** you designate (the same dedicated integration user described below), so that user's roles and table ACLs determine exactly what Serval can do. Serval does **not** request any OAuth scopes - the token is bounded entirely by the integration user's permissions, not by a scope list. * **Basic authentication** - Serval stores the integration user's **username and password** and sends them as standard HTTP Basic auth on every call. Use this when inbound OAuth client credentials aren't available on your instance, or for a quick test setup. Whichever method you choose, you create the **same** dedicated integration user and assign it the **same** roles and ACLs. The only difference is how Serval authenticates as that user. Serval only ever calls hosts ending in `service-now.com` - requests to any other host are refused before they leave Serval. Data flows both ways: Serval polls your instance for ticket and comment changes, keeps groups, roles, departments, companies, locations, and cost centers current with scheduled background syncs, and writes back (creating and updating incidents, problems, change requests, HR cases, and catalog requests) on demand when a workflow runs. Live agent handoff (Virtual Agent Bot-to-Bot) uses one extra shared token that is **not** part of the connect form. You generate it later from the ServiceNow app's **Ticket Syncing** tab - see [Live agent handoff](#live-agent-handoff-via-va-bot-to-bot-optional) at the end of this page. ## Get your credentials You configure everything on the **ServiceNow side first**, then paste two values into Serval. The authoritative provider reference is the [ServiceNow product documentation](https://www.servicenow.com/docs/); the exact clickpath for inbound OAuth is in ServiceNow's official guide, [Enable OAuth with inbound REST](https://www.servicenow.com/docs/bundle/yokohama-api-reference/page/integrate/inbound-rest/task/t_EnableOAuthWithREST.html). Use a **dedicated service account**, never a personal or full-admin account. Serval runs every call as this user, so least-privilege here is what bounds what Serval can do - and keeps your ServiceNow audit trail clean (`sys_created_by` / `sys_updated_by` will show this account). In ServiceNow, go to **User Administration → Users** and create a new user. Recommended values: | Field | Value | | - | - | | **User ID** | `serval.integration` | | **First name** | `Serval` | | **Last name** | `Integration` | | **Active** | Checked | | **Web service access only** | Checked (blocks interactive login) | | **Internal Integration User** | Checked (if available in your ServiceNow version) | Give the user **both a first and last name**. ServiceNow's inbound-OAuth user picker omits users that are missing either name - a known quirk of the picker (see this [ServiceNow Community thread](https://www.servicenow.com/community/developer-forum/zurich-integration-user-doesn-t-show-up-in-oauth-application/td-p/3502337)) - so you won't be able to select the account as the OAuth Application User later. If you plan to use **Basic authentication**, also click **Set Password → Generate Password** and copy the password now - you will not be able to view it again. You'll paste it into Serval. If you use OAuth 2.0, you typically do not need a password for Serval: API access is authorized via Client ID and Client Secret, and the integration user is designated on the OAuth application below. Creating a custom role with granular permissions is the **recommended approach** for production environments. It follows the principle of least privilege and provides better security than out-of-the-box roles like `itil` or `admin`. (The simpler OOB-role alternative is covered in the next step.) Go to **User Administration → Roles** and create: | Field | Value | | - | - | | **Name** | `x_serval_integration` | | **Description** | `Custom role for Serval integration with least-privilege API access` | Then open the role and, in the **Contains Roles** related list, add these base roles: | Role | Purpose | | - | - | | `rest_api_explorer` | Enables REST API access | | `personalize_choices` | Allows reading sys\_choice values | | `personalize_dictionary` | Allows reading sys\_dictionary for field definitions | These base roles provide the foundational REST API capabilities; granular table access comes from the ACLs in the next step. Serval requires specific read/write access to ServiceNow tables. Create Access Control List (ACL) rules that grant only the necessary permissions. Serval uses ServiceNow's **Table API**, **Service Catalog API**, **Attachment API** (all active by default), and the **Change Management REST API**, which requires the Change Management - REST API plugin (`com.snc.change_management.rest_api`) - active by default on most instances. #### Incident Management Tables | Table | Read | Create | Write | Purpose | | - | - | - | - | - | | `incident` | Yes | Yes | Yes | Incident records (all standard fields) | | `sys_journal_field` | Yes | - | - | Comments and work notes | #### HR Service Delivery Tables Required only if you sync or create HR cases. | Table | Read | Create | Write | Purpose | | - | - | - | - | - | | `sn_hr_core_case` | Yes | Yes | Yes | HR case records, including comments and work notes | #### Service Catalog Tables | Table | Read | Create | Write | Purpose | | - | - | - | - | - | | `sc_cat_item` | Yes | - | - | Catalog item details | | `sc_category` | Yes | - | - | Catalog categories | | `sc_request` | Yes | Yes | - | Service requests | | `sc_req_item` | Yes | Yes | Yes | Requested items | | `item_option_new` | Yes | - | - | Catalog item variable definitions | | `io_set_item` | Yes | - | - | Variable set to catalog item mapping | | `question_choice` | Yes | - | - | Choices for select-type catalog variables | | `catalog_script_client` | Yes | - | - | Catalog client scripts (fillability analysis, Understanding tab) | | `catalog_ui_policy` | Yes | - | - | Catalog UI policies (When/Show/Hide/Require rules) | | `catalog_ui_policy_action` | Yes | - | - | UI policy actions | | `sys_script_include` | Yes | - | - | Script includes referenced by catalog client scripts | | `sys_attachment` | - | Yes | - | File attachment uploads for requested items (written through the Attachment API, but the user still needs create permission) | `catalog_ui_policy`, `catalog_ui_policy_action`, `catalog_script_client`, and `sys_script_include` are the grants most often missed. They hold an item's design rather than what a requester sees when ordering, so the roles that let a user browse and order the catalog don't cover them, and ServiceNow ships them readable only by administrative roles. Each one needs two read rules, with no condition and no script on either: one named for the table, which admits its rows (`catalog_ui_policy`), and one named for its fields, which fills in the columns (`catalog_ui_policy.*`). The same pair applies to `catalog_ui_policy_action`, `catalog_script_client`, and `sys_script_include`. The **Check Catalog Import Permissions** health check reads all seven catalog-definition tables and names any it can't reach. See [Check Catalog Import Permissions fails with "User Not Authorized"](#gotchas-and-troubleshooting) if it fails. #### Configuration Tables (Read-Only) | Table | Read | Create | Write | Purpose | | - | - | - | - | - | | `sys_user` | Yes | - | - | User lookup for assignment | | `sys_user_group` | Yes | - | - | Assignment group lookup | | `sys_choice` | Yes | - | - | Field dropdown values | | `sys_dictionary` | Yes | - | - | Field definitions | | `cmdb_ci_service` | Yes | - | - | Business services | #### Knowledge Base Tables (Read-Only) | Table | Read | Create | Write | Purpose | | - | - | - | - | - | | `kb_knowledge_base` | Yes | - | - | Knowledge base metadata | | `kb_category` | Yes | - | - | Knowledge categories | | `kb_knowledge` | Yes | - | - | Knowledge articles | | `kb_article_template` | Yes | - | - | Article template metadata (templated articles) | | `kb_article_template_definition` | Yes | - | - | Article template definitions; templated articles also read their extended template tables | #### User Criteria Tables (Read-Only) These tables determine which users have access to knowledge articles and catalog items, and back the user criteria import. | Table | Read | Purpose | | - | - | - | | `user_criteria` | Yes | User criteria definitions (users, groups, companies, etc.) | | `kb_uc_can_read_mtom` | Yes | Knowledge article access - users who CAN read | | `kb_uc_cannot_read_mtom` | Yes | Knowledge article access - users who CANNOT read | | `sc_cat_item_user_criteria_mtom` | Yes | Catalog item access - users who CAN access | | `sc_cat_item_user_criteria_no_mtom` | Yes | Catalog item access - users who CANNOT access | On `user_criteria`, Serval reads every column that defines a criteria: `active`, `advanced`, `match_all`, `script`, `sys_scope`, and the seven condition columns `user`, `group`, `company`, `department`, `location`, `role`, and `cost_center`. Grant read on **every `user_criteria` column**, not only on the table. A field-level ACL that hides a condition column returns the row with that column blank or missing, and Serval cannot tell a hidden condition from an empty one. Serval detects a hidden column and fails closed: it refuses every **Match All** criteria and every criteria whose only condition is in the hidden column. The articles those criteria gate stay hidden from everyone in Serval until the column is readable. For example, a criteria written as a script plus a `location` condition with **Match All** cannot be evaluated while `location` is hidden. Serval's sync log names the hidden columns. #### Criteria Evaluation Tables (Read-Only) Serval keeps ServiceNow user criteria in sync along two paths, and every sync uses both: * **Fast path.** Serval evaluates a criteria itself, against a read-only snapshot of your instance, in one pass, minutes after a sync starts. It needs **read** on the tables below. Every criteria the integration account lets Serval evaluate takes this path. * **Standard path.** ServiceNow evaluates each remaining criteria for each user through the read-only Scripted REST endpoint you install (see [Script-based knowledge permissions](#script-based-knowledge-permissions-optional)). It needs only the User Criteria Tables and the System Property ACLs on this page. On a large instance a full pass takes hours. Serval chooses per criteria on every sync; nothing needs to be turned on. A criteria moves to the fast path the moment the read access it needs is in place, and the whole sync gets faster with it. A criteria neither path can answer **fails closed**: the articles it gates stay hidden in Serval. The sync log names the table or column that kept a criteria off the fast path. Serval also re-checks the fast path against ServiceNow: on every sync the endpoint re-evaluates a small page of users for the criteria the fast path answered, and the page moves through the whole user list over successive syncs. Serval records the pairs checked and the pairs that disagreed. **Identity tables.** Serval reads these columns, and only these: | Table | Columns Serval reads | Purpose | | - | - | - | | `sys_user` | `sys_id`, `user_name`, `email`, `first_name`, `last_name`, `name`, `title`, `vip`, `active`, `department`, `company`, `location`, `cost_center`, `manager`, `roles`, `employee_number`, `source`, `internal_integration_user`, `web_service_access_only`, `locked_out`, `preferred_language` | The users a criteria is evaluated for, and the attributes that conditions and scripts test | | `sys_user_has_role` | `user`, `role`, `inherited`, `state` | Role conditions and `gs.hasRole()` | | `sys_user_grmember` | `user`, `group` | Group conditions | | `sys_user_group` | `name`, `parent`, `active`, `manager`, `type`, `description`, `roles` | Group lookups in scripts | | `sys_user_role` | `name`, `description` | Role names in scripts | | `cmn_department` | `name`, `parent`, `dept_head`, `company` | Department conditions and dot-walks such as `department.name` | | `core_company` | `name`, `customer`, `vendor`, `manufacturer`, `country` | Company conditions | | `cmn_location` | `name`, `country`, `city`, `state`, `company` | Location conditions | | `cmn_cost_center` | `name`, `manager` | Cost center conditions | Field-level ACLs on `sys_user` matter as much as the table grant. Serval drops a user whose `active` or `preferred_language` value is hidden, because a blank there would change the answer, and that user then matches no criteria in Serval. Grant read on every column in the list. **Script context tables.** Advanced (script) criteria run inside Serval's evaluator, which reproduces the platform objects the scripts use. Serval reads these tables to do that: | Table | Columns Serval reads | Purpose | | - | - | - | | `sys_script_include` | `name`, `api_name`, `script`, `active` | Script includes that your criteria scripts call. Serval loads only the includes the scripts name, and the includes those call, up to six levels deep. | | `sys_extension_point` | `name`, `api_name` | Extension points that your scripts resolve by API name | | `sys_extension_instance` | `extension_point`, `script_include`, `order`, `active` | The implementations of those extension points | | `sys_plugins` | `source`, `active` | Plugin checks with `GlidePluginManager` | | `sys_scope` | `scope`, `active` | The application scope a scoped criteria runs in | | `sys_properties` (specific rows) | `name`, `value` | Every property that your scripts read with `gs.getProperty()`, plus the canary row `glide.war`. See System Property ACLs below. | | `sys_db_object` | `name`, `super_class` | The table hierarchy, so that `extends` and table-name checks resolve | | `sys_dictionary` | `name`, `element`, `reference` | Reference fields, so that dot-walks such as `gr.department.name` resolve | | Tables your scripts query | The columns the scripts read | Any table that an advanced criteria queries with `GlideRecord` beyond the identity tables, for example an HR criteria table. Serval loads it read-only, within size limits, and refuses the criteria when it cannot. | The identity tables overlap with the [Access Management & Resource Sync Tables](#access-management--resource-sync-tables) below. Knowledge permission sync needs **read** on them even when you do not use access profiles. No write access is needed for criteria evaluation. #### System Property ACLs (Read-Only) Required for [script-based knowledge permissions](#script-based-knowledge-permissions-optional) and for the fast path. Serval reads three `sys_properties` rows to decide how to fail on knowledge read criteria, and the fast path also reads every row that your criteria scripts pass to `gs.getProperty()`. Grant read on those rows the same way. `sys_properties` is **not** world-readable, and ServiceNow **silently filters** rows the user can't read down to an empty result (a `200`, not a `403`) - so a missing grant looks identical to an unset property and can flip Serval to the wrong default. Grant read on exactly these three rows with **record-level** ACLs (Type `record`, Operation `read`, conditioned on `name` = the row below) rather than opening the whole table: | `sys_properties` row (`name`) | Read | Purpose | | - | - | - | | `glide.knowman.apply_article_read_criteria` | Yes | Whether article read-criteria enforcement is turned on | | `glide.knowman.block_access_with_no_user_criteria` | Yes | Whether a knowledge base with no criteria denies access rather than being treated as public | | `glide.war` | Yes | Readability canary - present on every instance, so Serval can tell "property unset" from "row unreadable" | #### Change Management Tables | Table | Read | Create | Write | Purpose | | - | - | - | - | - | | `change_request` | Yes | Yes | Yes | Change request records | | `sysapproval_approver` | Yes | - | Yes | Change request approval records (write is needed to act on approvals) | Creating change requests uses the Change Management REST API, which requires the **Change Management - REST API** plugin (`com.snc.change_management.rest_api`) to be active on your ServiceNow instance. This plugin is active by default on most instances. #### Problem Management Tables | Table | Read | Create | Write | Purpose | | - | - | - | - | - | | `problem` | Yes | Yes | Yes | Problem records | #### Access Management & Resource Sync Tables These tables are required if you use Serval's access profile capabilities for syncing organizational resources and provisioning/deprovisioning users. If you are not using access profiles, you can skip the **create** and **write** grants here. The `sys_user` and `sys_user_group` tables listed above under Configuration Tables still require **read** access for basic functionality regardless, and knowledge permission sync needs **read** on the identity tables listed under [Criteria Evaluation Tables](#criteria-evaluation-tables-read-only). | Table | Read | Create | Write | Delete | Purpose | | - | - | - | - | - | - | | `sys_user` | - | - | Yes | - | Write access for department assignment (read access already listed above) | | `sys_user_grmember` | Yes | Yes | - | Yes | Group membership provisioning and deprovisioning | | `sys_user_role` | Yes | - | - | - | Role definitions for resource sync | | `sys_user_has_role` | Yes | Yes | - | Yes | Role assignment provisioning and deprovisioning | | `core_company` | Yes | - | - | - | Company records for resource sync | | `cmn_department` | Yes | - | - | - | Department records for resource sync | | `cmn_location` | Yes | - | - | - | Location records for resource sync | | `cmn_cost_center` | Yes | - | - | - | Cost center records for resource sync | For each table that requires access, create appropriate ACLs: 1. In the navigator, search for **"Access Control (ACL)"** 2. Select **System Security → Access Control (ACL)** ServiceNow checks two ACLs on every read: a **table-level** rule named after the table decides whether the user can reach the table at all, and a **field-level** rule named `.*` decides which field values come back. The integration user needs both. For each table that requires **read** access, create the table-level ACL: 1. Click **New** 2. Set **Type** to `record` 3. Set **Operation** to `read` 4. Set **Name** to the table name (for example `incident`), leaving the field part of the name as **-- None --** 5. In the **Requires role** related list, add your custom role `x_serval_integration` 6. Click **Submit** Then create the field-level ACL for the same table: repeat the steps with the field part of **Name** set to `*` (so the rule is named `incident.*`). Repeat both for all tables listed in the Required Table Access tab. The two rules fail differently. A missing table-level rule returns `403` with *"User is unauthorized to access table"* and the table name, which the health checks report. A missing field-level rule returns `200` with the rows present but their fields stripped. Because the rows are there, the **Check Catalog Import Permissions** health check counts the table as readable and passes with no warning at all, so the only symptom is imported data with blank definitions. For tables that require **create**, **write**, or **delete** access: 1. Click **New** 2. Set **Type** to `record` 3. Set **Operation** to `create`, `write`, or `delete` as needed 4. Set **Name** to the table name 5. In the **Requires role** related list, add your custom role `x_serval_integration` 6. Click **Submit** Create ACLs for the following tables: **Incident, Problem & HR Case Management:** * `incident` (create, write) * `problem` (create, write) * `sn_hr_core_case` (create, write - only if you use HR cases) **Change Management:** * `change_request` (create, write) * `sysapproval_approver` (write) **Service Catalog:** * `sc_request` (create) * `sc_req_item` (create, write) * `sys_attachment` (create) **Access Management (if using access profiles):** * `sys_user` (write) * `sys_user_grmember` (create, delete) * `sys_user_has_role` (create, delete) Using out-of-the-box roles is simpler but grants **more permissions than necessary**. Only use this approach for development/testing or if your organization's security policy permits. Instead of creating custom ACLs, you can assign these out-of-the-box roles to the integration user: | Role | Purpose | Notes | | - | - | - | | `itil` | ITSM functionality (incidents, problems, changes) | Grants broad access to incident, problem, and change management | | `catalog` | Service catalog access | For catalog item browsing, ordering, and request management | | `knowledge` | Knowledge base access | For knowledge article sync | | `user_admin` | User and group administration | Required only if using access profiles for provisioning/deprovisioning | | `catalog_admin` | Catalog item design (UI policies and their actions) | Required for catalog import: `catalog` covers browsing and ordering, not the tables that define an item | `catalog_admin` doesn't cover `catalog_script_client` or `sys_script_include`: ServiceNow documents it as excluding scripting functions, and names no role below `admin` for reading script includes. Even on this path, create the table-level and field-level **read** ACLs for those two tables from the Create ACLs tab, or the **Check Catalog Import Permissions** health check fails and imported items lose their script-driven behavior. To see which roles your instance's ACLs require for any table, open `sys_security_acl_role.list` and filter by the table name and the read operation. The `itil` role includes access to the Change Management REST API. If you use the custom role approach instead, ensure the **Change Management - REST API** plugin (`com.snc.change_management.rest_api`) is active on your instance. To assign roles: 1. Open the integration user record 2. Scroll to the **Roles** related list 3. Click **Edit** 4. Add the roles from the list above 5. Click **Save** 1. Navigate to **User Administration → Users** and open the `serval.integration` user 2. Scroll down to the **Roles** related list and click **Edit** 3. Add the `x_serval_integration` role (or the OOB roles if you chose that approach) 4. Click **Save** Inbound OAuth client credentials are **disabled by default** on most ServiceNow instances. In **System Properties** (`sys_properties.list`), find or create: | Field | Value | | - | - | | **Name** | `glide.oauth.inbound.client.credential.grant_type.enabled` | | **Type** | true \| false | | **Value** | `true` | | **Application** | `Global` | If this property is missing or `false`, **every** token request to `oauth_token.do` fails with `access_denied`, no matter how the OAuth app is configured. This is the single most common cause of a failed OAuth connection. ServiceNow may also display a banner on the Application Registry form warning that the property is disabled. ServiceNow documents this requirement in its official guide, [Up your OAuth 2.0 game: Inbound Client Credentials](https://www.servicenow.com/community/developer-blog/up-your-oauth2-0-game-inbound-client-credentials-with-washington/ba-p/2816891). Go to **System OAuth → Application Registry → New**. ServiceNow shows a list of OAuth application types - pick the one for **inbound** access (external systems calling **into** your instance). Do **not** choose **Connect to a third party OAuth Provider** or other outbound options; those are for ServiceNow calling external OAuth servers, not for Serval. * **Recommended:** **New Inbound Integration Experience** - the current UI for inbound OAuth, including client credentials. When the wizard asks **Select your application connection type**, choose **OAuth - Client credentials grant** (machine-to-machine). Do not choose Authorization code, JWT bearer, Resource owner password, or third-party ID token flows for the Serval integration. * **Alternative:** **\[Deprecated UI] Create an OAuth API endpoint for external clients** - the older wizard for the **same** kind of inbound app. "Deprecated UI" refers to ServiceNow replacing the screen flow, not to the credentials; it still produces a working Client ID / Client Secret. Some teams see odd default forms here (for example, the OAuth Application User field hidden until you change the form layout); using the New Inbound Integration Experience often avoids that. ServiceNow modal Select your application connection type showing five options; OAuth Client credentials grant is highlighted as the choice for Serval Give the application a clear name (for example, `Serval integration`) and save; ServiceNow auto-generates the Client Secret. Then: 1. Set **Client type** to run API calls as your integration account - for example **Integration as a Service** (wording varies by release). That tells ServiceNow which `sys_user` supplies roles, ACLs, and audit fields for requests made with a client-credentials token. 2. Allow the **Client credentials** grant. Often this is not on the main form: open the **OAuth Entity** or **OAuth Entity Profile** related list on the same Application Registry record, open the related row, and confirm **Client credentials** is enabled. Save that record if you changed it. 3. Set the **OAuth Application User** to your `serval.integration` user, so issued tokens act as that account. If you don't see an **OAuth Application User** field on the form, ServiceNow hides it on the default layout. Open the form's context menu → **Configure → Form Layout**, move **OAuth Application User** from *Available* to *Selected*, save, and reload. Some instances instead expose the value as a column in the Application Registry **list view**, or on the related **OAuth Entity Profile** row. On the newer Inbound Integration UI, only the first 1,000 users (alphabetical) appear in the picker - a [documented ServiceNow known error](https://support.servicenow.com/kb?id=kb_article_view\&sysparm_article=KB2624687) - search precisely for your account. The integration user must already have the roles and ACLs from the earlier steps so token-backed API calls are authorized correctly. From the OAuth application record, copy the **Client ID** and **Client Secret** (click the lock icon to reveal the secret). Store them securely - anyone holding both can mint tokens that act as your integration user. Your **Instance Name** is the subdomain of your ServiceNow URL: if your instance lives at `https://mycompany.service-now.com`, the instance name is `mycompany`. You'll enter it in Serval next. ## Connect in Serval In Serval, open **Integrations → All integrations → ServiceNow → Connect** and complete the form. The fields that appear depend on the **Authentication method** you pick. **Instance Name** - the subdomain of your ServiceNow instance. For `https://mycompany.service-now.com`, enter `mycompany`. You can paste the full URL (e.g. `https://mycompany.service-now.com/now/nav`) - Serval strips the scheme, path, port, and the `.service-now.com` suffix and lowercases what's left. If the result isn't a single valid subdomain, you'll see *"Instance Name must be the subdomain of your ServiceNow instance (e.g. 'mycompany' for mycompany.service-now\.com)"*. Enter a **Connection Name**, such as `IT Service Account`, to distinguish accounts connected to the same ServiceNow instance. Leave it blank to use the instance name. The name is a display label; changing it doesn't create a separate connection. **Authentication method** defaults to **OAuth 2.0 (Client Credentials)**. The remaining fields switch based on your choice: | Field | What to paste | | - | - | | **Client ID** | The Client ID from your ServiceNow OAuth application. | | **Client Secret** | The Client Secret from the same OAuth application. | | Field | What to paste | | - | - | | **Username** | The User ID of your integration user (e.g. `serval.integration`). | | **Password** | The password you set for that user. | Leave this blank unless you've installed the script-based knowledge-permissions endpoint - if you have, paste the **API namespace** from your **Serval ACL** Scripted REST API here (see [Script-based knowledge permissions](#script-based-knowledge-permissions-optional)). Serval ServiceNow connection screen showing the optional ACL Endpoint API Namespace field Save. Serval immediately tries to authenticate against your instance. If anything is off (wrong instance, bad credentials, or inbound OAuth not enabled), ServiceNow's error surfaces back to you. When you later **edit** the connection, secret fields show as masked placeholders. Leave them untouched to keep the stored values; only retype a field to change it. Switching auth methods (OAuth ↔ Basic) does require you to enter that method's credentials fresh. **Connection Name** shows the current display name; clearing it resets the label to the instance name. Editing preserves the connection's ID and existing workflow references. ### Connect multiple accounts to the same instance To add another connection, repeat the connection steps with the same **Instance Name** and a different **Username** for Basic authentication or **Client ID** for OAuth 2.0. Each account gets a separate connection with its own credentials. For OAuth, different client IDs create separate connections even if they use the same OAuth Application User. Connecting the same instance, authentication method, and username or client ID again updates the existing connection's credentials. To rotate credentials or switch authentication methods while keeping the same connection, edit that connection instead of starting a new one. If you use [Business Rule comment webhooks](#real-time-comment-sync-via-webhook-optional), enable them on only one ticket source per ServiceNow domain. ## Verifying the connection Open the ServiceNow app's **API Integration** tab and run the health checks. They confirm Serval can authenticate as your integration user and exercise the real surfaces it uses: * **Test ServiceNow Connection** - authenticates and queries your user table (a single row). Success reads *"Successfully authenticated with ServiceNow"*. Failure reads *"Unable to connect to ServiceNow. Please verify your credentials are valid and have the necessary permissions."* * **List ServiceNow Users** - samples up to ten rows from `sys_user`. Success reports the sample size; failure reads *"Unable to list users from ServiceNow. Please verify the credentials have permission to read the sys\_user table."* * **List ServiceNow Incidents**, **List ServiceNow Knowledge Articles**, **List ServiceNow Catalog Items**, and **List ServiceNow User Criteria** - the same ten-row sample pattern against `incident`, `kb_knowledge`, `sc_cat_item`, and `user_criteria`. Each failure message names the table the credentials couldn't read. * **Check Catalog Import Permissions** - reads one row from each of the seven catalog-definition tables the importer walks: `item_option_new`, `io_set_item`, `question_choice`, `catalog_ui_policy`, `catalog_ui_policy_action`, `catalog_script_client`, and `sys_script_include`. Success reads *"The integration user can read all 7 ServiceNow tables required for catalog import."* A failure lists the blocked tables and quotes ServiceNow's response for each one, under *"The integration user cannot read N of the 7 ServiceNow tables required for catalog import."* A table that answers with no rows still passes, with a note: row-level ACLs hide rows silently, so an empty answer can also be a permission gap. A table that answers with rows but no fields, which is what a missing `
.*` rule produces, passes with no note at all, because the check only counts rows. If this check fails while **List ServiceNow Catalog Items** passes, or passes while imports still come back without UI policies or client scripts, see the entry [Check Catalog Import Permissions fails with "User Not Authorized"](#gotchas-and-troubleshooting) under troubleshooting. A deeper lifecycle health check **creates real records on your instance**: it looks up the `serval.integration` user, creates a temporary incident whose short description begins with "Health Check Test Incident", drives it through state transitions (New → In Progress → On Hold with a hold reason → In Progress), resolves it, creates additional short-lived incidents to exercise impact/urgency permutations (all resolved afterwards), and places a test catalog request against your first active catalog item, then closes the requested item. Test incidents are **resolved, not deleted** - seeing "Health Check Test" records appear and resolve is expected. The resolution-codes check fails if your instance has no resolution codes defined. The user lookup is hard-coded to the `serval.integration` user name - if you chose a different User ID in [Get your credentials](#get-your-credentials), this check fails at the user-lookup step even though the connection itself is healthy. A green Test Connection but a failing list check almost always means the integration user is missing a table ACL (for example, read on `kb_knowledge` or `user_criteria`). The failing check names the table it couldn't reach. ## Gotchas and troubleshooting This means ServiceNow **rejected the token request** at `oauth_token.do` - not a Serval storage problem. Work through these on the ServiceNow side, most common first: 1. **Inbound client credentials enabled** - `glide.oauth.inbound.client.credential.grant_type.enabled` must be `true` in **Global** scope. This is the number-one cause. 2. **OAuth Application User set** - the app must be tied to your integration user, and that user must be **Active** with the right roles/ACLs. 3. **Client credentials grant allowed** - confirm it's enabled on the app (or its OAuth Entity / Entity Profile record). 4. **Client ID / Secret correct** - re-copy from ServiceNow with no leading or trailing spaces. If you rotated the secret in ServiceNow, update the Serval connection too. If all four checks above pass and the token request still fails, the cause is on the ServiceNow side rather than in how Serval formats the request - contact **[support@serval.com](mailto:support@serval.com)**. ServiceNow's inbound-OAuth user picker omits accounts that are **missing a first or last name** - a known quirk of the picker (see this [ServiceNow Community thread](https://www.servicenow.com/community/developer-forum/zurich-integration-user-doesn-t-show-up-in-oauth-application/td-p/3502337)). Populate both names on the user, confirm it's **Active**, and reload. On the newer Inbound Integration experience, only the first 1,000 users alphabetically are listed - a [documented ServiceNow known error](https://support.servicenow.com/kb?id=kb_article_view\&sysparm_article=KB2624687) - so search precisely. If the field itself is absent, add it via **Configure → Form Layout** as described in [Get your credentials](#get-your-credentials). Serval normalizes whatever you paste down to a single subdomain. Blank input returns *"Instance Name is required"*. Anything that doesn't reduce to a valid DNS label returns *"Instance Name must be the subdomain of your ServiceNow instance (e.g. 'mycompany' for mycompany.service-now\.com)"*. Enter just `mycompany` (or paste the full URL and let Serval trim it) - don't enter an IP, a non-`service-now.com` host, or extra path segments that aren't part of the subdomain. Serval enforces complete credentials per method: * OAuth: *"Client ID and Client Secret are required for OAuth 2.0"* (or *"Client ID and Client Secret are required when switching to OAuth 2.0"* if you changed methods). * Basic: *"Username and Password are required for Basic Auth"* (or *"Username and Password are required when switching to Basic Auth"*). When you're only editing an existing OAuth or Basic connection, you can leave the masked fields as-is; Serval keeps the stored values. But **switching** auth methods requires entering that method's credentials in full. ServiceNow choice fields (like `close_code`, `category`, `priority`) silently ignore invalid values - the API returns 200 but the field stays empty, and a downstream Data Policy then blocks the state change. Valid choice values are **instance-specific**, so Serval's helpers and workflows query them rather than hard-coding. If a workflow write isn't sticking, the usual cause is an instance Business Rule, write ACL, or Data Policy on the target table - those are configured in ServiceNow and can't be worked around from Serval. Change-request creation needs the **Change Management - REST API** plugin (`com.snc.change_management.rest_api`) active. Most state transitions also require an **assignment group** to be set - set it at creation time, since adding it later is often blocked. Change approvals live in a **separate table** (`sysapproval_approver`), so the integration user needs write access there for approval workflows to work. A `403` from the Change Management API usually means a state-model condition isn't met; a `400` naming a rule means a Business Rule is blocking. Each surface needs its own read ACLs on the integration user's role. Empty knowledge sync → check read on the `kb_*` tables; empty catalog → check the catalog definition tables; empty access profiles → check the `user_criteria` and organizational tables. The matching health check (knowledge articles, catalog items, user criteria) will name the table it couldn't read. **Test ServiceNow Connection** and **List ServiceNow Catalog Items** pass, but this check reports that the integration user can't read some of the seven catalog-definition tables, quoting ServiceNow's `403` for each one: ```json theme={null} { "error": { "message": "User Not Authorized", "detail": "User is unauthorized to access table: catalog_ui_policy" }, "status": "failure" } ``` The tables that usually fail together are `catalog_ui_policy`, `catalog_ui_policy_action`, `catalog_script_client`, and `sys_script_include`. They hold an item's design - its UI policies and their actions, its client scripts, and the script includes those scripts call - and browsing or ordering the catalog never reads them, so a user who can read `sc_cat_item` and the variable tables is still locked out of them. Out of the box, ServiceNow grants them only to administrative roles: `catalog_admin` covers the UI policy tables but is documented as excluding scripting functions, and ServiceNow's documentation names no role below `admin` for reading script includes. The import doesn't stop when these reads fail. The item imports without them, so its form is missing the show, hide, and require rules and the script-driven behavior it has in ServiceNow, and the fillability analysis that decides whether an item can be a form runs without seeing its scripts. An item that should have fallen back to a link can import as a form that misbehaves. To fix it, grant the integration user's role **read** on each table the check names, at both levels described in the **Create Read ACLs** step of [Get your credentials](#get-your-credentials): a table-level ACL named after the table (for example `catalog_ui_policy`) and a field-level ACL named `catalog_ui_policy.*`. That `403` means the table-level rule is missing. If the check passes clean and imported items still have no rules, the field-level rule is the one missing: rows come back with their fields stripped, and the check counts rows only. Once the rules are in place, re-run the health check, then use **Sync now** or wait for the next catalog sync: items imported while the reads were failing are regenerated on the next sync. Items someone has edited in Serval since their import are left alone by the sync, so re-import those by hand. **The check passes, but imports and Catalyst still see no UI policies or client scripts.** The check reads one row per table with no filter, so a table that answers `200` with no rows passes with a note. ServiceNow evaluates the roles on a record ACL first, then its condition, then its script, and a row that fails the condition or script is dropped from the response with no error. So a read ACL that carries a condition or script, or an integration user added to an out-of-the-box rule that has one, opens the table without letting the account see any rows in it. To confirm, impersonate the integration user in ServiceNow and open the `catalog_ui_policy` list: an empty list that reports rows removed by security constraints is this problem, and **Debug Security Rules** names the rule that fails. The fix is a read ACL on the table and on `
.*` that requires the integration role and has no condition and no script. No `admin` role is needed. The **Catalog filter** in Sync settings is a ServiceNow encoded query that is combined (AND) with the standard active-items filter - a filter that matches nothing imports nothing. The sync also **fails loudly if the integration user lacks the ACLs needed to run the query** against the catalog tables, so if a previously working sync breaks right after adding a filter, check the filter syntax first and the integration user's catalog-table read access second. Configured intervals are a **minimum interval, not an exact schedule**: the platform's scheduled ticks simply skip a sync until the configured interval has elapsed since the last completed run. Entity ingestion ticks every 4 hours, so entity-sync values at or below 4 hours behave like **Default (4 hours)** - only Every 6 hours, Every 12 hours, Once a day, and Once a week genuinely slow things down. Catalog sync fan-out runs every 30 minutes by default. That's by design. While **Import to Serval Knowledge Base** is enabled, mirrored documents are sync-locked - ServiceNow remains the source of truth and re-syncs update the Serval copy in place. Edit the article in ServiceNow (the document banner has a **View in ServiceNow** link). Disabling the toggle stops future writes but keeps already-imported pages rather than deleting them. Serval falls back to link-only automatically when it can't faithfully render the form: client scripts, scripted UI policies, UI scripts, unsupported required field types, or dynamic JavaScript reference qualifiers. The item's Understanding tab shows exactly which of these applies. You can keep it as a link, or use **Improve with Catalyst** to redesign the form as a conversational experience that works around those constraints. Criteria backed by ServiceNow **match scripts** show a **Cannot be fully mirrored** warning - Serval imports the declarative parts (groups, roles, attributes, users) but cannot execute the script. And a criterion with **no captured conditions** imports as an access profile that matches everyone on the team - Serval warns before you import it. Review the **Proposed access profile** preview before confirming. ServiceNow's journal and description fields render plain text only. Serval's built-in ticket sync converts formatting automatically (see [How formatting translates to ServiceNow](#how-formatting-translates-to-servicenow)), but a custom workflow that writes Serval-authored content directly into description, comments, work notes, or close notes should first run it through the markdown-to-ServiceNow-text helper in the ServiceNow SDK - otherwise bold markers, bullets, and link syntax appear verbatim in the record. You can switch methods on an existing connection without recreating it - just change **Authentication method** and enter the new method's credentials. Serval clears the old method's stored secret when you switch, so there's no stale password or client secret left behind. The existing Serval connection and its workflow references are preserved. *** ## Real-time comment sync via webhook (optional) By default, Serval polls your ServiceNow instance to sync comments. For faster, near-instant comment delivery, you can configure a Business Rule that pushes new comments to Serval via webhook. This applies to comments on Incidents, HR cases, and Catalog Requested Items that were created by the Serval integration. When you connect multiple accounts to the same instance, enable Business Rule comment webhooks on only one ticket source for that ServiceNow domain. Use polling for the other connections. The domain identifies the destination, so Serval rejects a webhook if more than one enabled ticket source matches it. This restriction doesn't apply to live-agent webhooks, whose URL identifies the connection. This requires a single Business Rule on the `sys_journal_field` table. No ServiceNow plugins, store apps, or additional licensing are required. ### How it works When a comment is added to a Serval-managed record, an **async insert** Business Rule fires on the `sys_journal_field` table. The rule verifies the parent record was opened by the Serval service account (the dedicated integration user you created in [Get your credentials](#get-your-credentials)), constructs a JSON payload, and sends it asynchronously to the Serval webhook. Serval processes the event and delivers the comment to the relevant conversation in real time - entries on the `comments` field surface as public replies, entries on `work_notes` surface as internal notes. The script filters on the parent record's **opened\_by** field, not on table name - it fires for journal entries on any record opened by the Serval service account. Serval's webhook handler processes events for `incident`, `sn_hr_core_case`, and `sc_req_item` records. ### Get your webhook token The webhook carries a per-environment token that Serval provides during onboarding, sent in the `X-Serval-Webhook-Token` header (server-side verification of this token is on the roadmap; the token is forwarded with each event today). Contact **[support@serval.com](mailto:support@serval.com)** to obtain your token before creating the Business Rule. For production, store it in a System Property (for example `x_serval.webhook_token`) rather than hard-coding it in the script. ### Webhook endpoint | Property | Value | | :- | :- | | **URL** | `https://svwebhook.api.serval.com/servicenow/new-comment` | | **Method** | `POST` | | **Content-Type** | `application/json` | | **Authentication** | Token via `X-Serval-Webhook-Token` header | The Business Rule sends a JSON body with these fields. `record_sys_id`, `comment.sys_id`, and a parseable `instance_url` are required; Serval routes the event to your integration install by the instance domain. | Field | Type | Description | | :- | :- | :- | | `instance_url` | string | Your ServiceNow instance URL | | `table` | string | Source table: `incident`, `sn_hr_core_case`, or `sc_req_item` | | `record_sys_id` | string | `sys_id` of the parent record | | `number` | string | Record number, e.g. `INC0012345`, `HRC0001234`, `RITM0056789` | | `comment.sys_id` | string | `sys_id` of the journal entry | | `comment.element` | string | `comments` (public reply) or `work_notes` (internal note) | | `comment.value` | string | The comment body text | | `comment.sys_created_by` | string | `user_name` of the commenter (must be a ServiceNow user\_name - Serval resolves it to attribute the comment) | | `comment.sys_created_on` | string | ServiceNow timestamp | ### Create the Business Rule In ServiceNow, go to **System Definition → Business Rules** and click **New**. Set the following fields: | Field | Value | | :- | :- | | **Name** | `Serval - Sync Comment to Webhook` | | **Table** | `sys_journal_field` | | **Advanced** | Checked | | **When** | `async` | | **Insert** | Checked | | **Update** | Unchecked | | **Delete** | Unchecked | | **Query** | Unchecked | ServiceNow Business Rule configuration showing the When to run tab with async timing, Insert checked, and the sys_journal_field table selected Switch to the **Advanced** tab and paste the following script: ServiceNow Business Rule Advanced tab showing the webhook script in the script editor ```javascript theme={null} (function executeRule(current, previous /*null when async*/) { var tableName = current.getValue('name'); var elementType = current.getValue('element'); // Validate: only Serval-managed records. // Replace 'serval.integration' with the user_name of your // Serval service account if it differs. var SERVAL_USER = 'serval.integration'; var recordSysId = current.getValue('element_id'); var parentRecord = new GlideRecord(tableName); if (!parentRecord.get(recordSysId)) { gs.warn('Serval webhook: parent record not found: ' + tableName + '/' + recordSysId); return; } var openedBy = parentRecord.opened_by.user_name.toString(); if (openedBy !== SERVAL_USER) { return; } // Build payload var instanceName = gs.getProperty('instance_name'); var instanceUrl = 'https://' + instanceName + '.service-now.com'; var payload = { instance_url: instanceUrl, table: tableName, record_sys_id: recordSysId, number: parentRecord.getValue('number'), comment: { sys_id: current.getUniqueValue(), element: elementType, value: current.getValue('value'), sys_created_by: current.getValue('sys_created_by'), sys_created_on: current.getValue('sys_created_on') } }; // Configuration // Replace the token value with the token provided by Serval. // For production, store this in a System Property // (e.g., x_serval.webhook_token) and retrieve it via // gs.getProperty('x_serval.webhook_token'). var SERVAL_WEBHOOK_URL = 'https://svwebhook.api.serval.com/servicenow/new-comment'; var SERVAL_WEBHOOK_TOKEN = ''; try { var request = new sn_ws.RESTMessageV2(); request.setEndpoint(SERVAL_WEBHOOK_URL); request.setHttpMethod('POST'); request.setRequestHeader('Content-Type', 'application/json'); request.setRequestHeader('X-Serval-Webhook-Token', SERVAL_WEBHOOK_TOKEN); request.setRequestBody(JSON.stringify(payload)); // Run asynchronously so we don't block the user's transaction request.setEccParameter('skip_sensor', 'true'); var response = request.executeAsync(); gs.info('Serval webhook: sent ' + elementType + ' event for ' + tableName + '/' + parentRecord.getValue('number') + ' (async)'); } catch (e) { gs.error('Serval webhook: failed to send event: ' + e.message); } })(current, previous); ``` The script references `serval.integration` as the Serval service account `user_name`. This must match the `user_name` of the integration user you created in [Get your credentials](#get-your-credentials). If you chose a different User ID, update the `SERVAL_USER` variable accordingly. Click **Submit** to save the rule. Comment sync will begin working immediately for Serval-managed records. *** ## Script-based knowledge permissions (optional) ServiceNow gates knowledge articles with **user criteria** - including script-based ("Advanced") and "Match All" criteria - that decide who is allowed to read each article. Serval honors those same rules along two paths, and every sync uses both. * **Fast path: Serval evaluates.** Serval evaluates a criteria itself, against a read-only snapshot of your instance, whenever the integration account can read what the criteria needs. That needs the read grants listed under [Criteria Evaluation Tables](#criteria-evaluation-tables-read-only). * **Standard path: this endpoint.** For every other criteria, Serval asks ServiceNow itself which users match, through a small read-only **Scripted REST API** you install on your instance. Serval never parses or reimplements your criteria scripts on this path; ServiceNow evaluates them with its own engine and returns the result, which Serval syncs. It needs no read grants beyond the User Criteria Tables and System Property ACLs. Serval also uses this endpoint to re-check the fast path's answers on a rotating page of users. A criteria neither path can answer is hidden from everyone in Serval - the safe default. Installing the endpoint is what makes script-gated knowledge answerable by the AI agent when the fast path cannot evaluate it. This endpoint is a **global-scope paste-in**: you create one Scripted REST API and paste a resource script. No plugins, store apps, or additional licensing are required. ### Prerequisites * Knowledge sync is already configured for this ServiceNow connection (see the knowledge base setup earlier on this page). * The Serval service account has the read grants from [Get your credentials](#get-your-credentials) - the **User Criteria Tables** plus the three **System Property ACLs** described there. Those grants are what let the endpoint (and the knowledge read-criteria fail-closed logic) work correctly, so set them up first. * If your instance uses **domain separation**, the Serval service account must be in the **global** domain. A domain-restricted account sees only a slice of the user and group tables, so the endpoint refuses to compute criteria membership for such an account (it reports every criteria as errored and Serval keeps the last known access state) rather than risk hiding articles from the wrong people. ### Create the Scripted REST API In ServiceNow, go to **System Web Services → Scripted REST APIs** and click **New**. Fill in: | Field | Value | | - | - | | **Name** | `Serval ACL` | | **API ID** | `serval_acl` | Save. On the **Serval ACL** service, in the **Resources** related list, click **New**. Fill in: | Field | Value | | - | - | | **Name** | `matching_criteria` | | **HTTP method** | `POST` | | **Relative path** | `/matching_criteria` | | **Requires authentication** | Checked | | **Requires ACL authorization** | Checked | Then paste the following script into the resource's **Script** field: ```javascript theme={null} /** * Serval ACL evaluation endpoint (matching_criteria). * * Paste this file verbatim into the Script field of the Serval ACL Scripted * REST API's POST /matching_criteria resource. Do not modify: the wire * contract, semantics, and install guide are maintained in Serval's source * repository (integrations/integrations/src/servicenow/acl-endpoint/README.md), * and the sync verifies SERVAL_ACL_VERSION on every response. */ (function process(request, response) { var SERVAL_ACL_VERSION = "1.2.0"; var MAX_USERS_PER_REQUEST = 500; var MAX_CRITERIA_PER_REQUEST = 5000; var MAX_CRITERIA_PER_MATCHING_USERS_REQUEST = 100; var MAX_MEMBERS_PER_CRITERIA = 10000; var MAX_GROUP_NESTING_DEPTH = 10; var SYS_ID_IN_CHUNK = 100; var body = readJsonBody(request); if (body === null) { return respondError( response, 400, "invalid_json", "Request body is not valid JSON, or is not a JSON object." ); } if (!isOptionalArray(body.user_sys_ids)) { return respondError( response, 400, "invalid_request", "user_sys_ids must be an array when present." ); } if (!isOptionalArray(body.criteria_sys_ids)) { return respondError( response, 400, "invalid_request", "criteria_sys_ids must be an array when present." ); } var requestedUsers = toStringSet(body.user_sys_ids); var requestedCriteria = toStringSet(body.criteria_sys_ids); if (("" + (body.mode || "")).trim() === "matching_users") { return respondMatchingUsers( response, requestedCriteria, toNonNegativeInt(body.member_offset, 0), toBoundedInt( body.member_limit, MAX_MEMBERS_PER_CRITERIA, MAX_MEMBERS_PER_CRITERIA ) ); } if (requestedUsers.length > MAX_USERS_PER_REQUEST) { return respondError( response, 400, "too_many_users", "user_sys_ids exceeds " + MAX_USERS_PER_REQUEST + "; chunk the request." ); } if (requestedCriteria.length > MAX_CRITERIA_PER_REQUEST) { return respondError( response, 400, "too_many_criteria", "criteria_sys_ids exceeds " + MAX_CRITERIA_PER_REQUEST + "; chunk the request." ); } var criteria = loadCriteria(requestedCriteria, MAX_CRITERIA_PER_REQUEST); if (criteria.truncated) { return respondError( response, 400, "too_many_criteria", "instance has more than " + MAX_CRITERIA_PER_REQUEST + " active criteria; send an explicit criteria_sys_ids list." ); } if (criteria.ids.length > 0 && !criteriaLoaderAvailable()) { return respondError( response, 500, "evaluator_unavailable", "sn_uc.UserCriteriaLoader.getMatchingCriteria is not available on this instance." ); } var userOffset = toNonNegativeInt(body.user_offset, 0); var userLimit = toBoundedInt( body.user_limit, MAX_USERS_PER_REQUEST, MAX_USERS_PER_REQUEST ); var users = loadUsers(requestedUsers, userOffset, userLimit); var matches = {}; var errored = []; var i; for (i = 0; i < users.found.length; i++) { var userSysId = users.found[i]; try { matches[userSysId] = evaluate(userSysId, criteria.ids); } catch (e) { errored.push(userSysId); } } var out = { serval_acl_version: SERVAL_ACL_VERSION, matches: matches, criteria: criteria.meta, unresolved_user_sys_ids: users.unresolved, errored_user_sys_ids: errored, }; return respondJson(response, 200, out); function readJsonBody(req) { try { if (!req.body) { return {}; } var raw = req.body.dataString; if (raw === null || raw === undefined || ("" + raw).trim() === "") { return {}; } var parsed = JSON.parse("" + raw); if (parsed === null || typeof parsed !== "object" || isArray(parsed)) { return null; } return parsed; } catch (e) { return null; } } function criteriaLoaderAvailable() { try { return ( typeof sn_uc !== "undefined" && !!sn_uc.UserCriteriaLoader && typeof sn_uc.UserCriteriaLoader.getMatchingCriteria === "function" ); } catch (e) { return false; } } function loadCriteria(ids, cap) { var meta = []; var resolvedIds = []; if (ids.length === 0) { var all = new GlideRecord("user_criteria"); all.addActiveQuery(); all.orderBy("sys_id"); all.setLimit(cap + 1); all.query(); collectCriteria(all, resolvedIds, meta); return { ids: resolvedIds, meta: meta, truncated: resolvedIds.length > cap, }; } var chunks = chunk(ids, SYS_ID_IN_CHUNK); var c; for (c = 0; c < chunks.length; c++) { var gr = new GlideRecord("user_criteria"); gr.addQuery("sys_id", "IN", chunks[c].join(",")); gr.addActiveQuery(); gr.query(); collectCriteria(gr, resolvedIds, meta); } return { ids: resolvedIds, meta: meta, truncated: false }; } function collectCriteria(gr, resolvedIds, meta) { while (gr.next()) { var sysId = gr.getUniqueValue(); resolvedIds.push(sysId); meta.push({ sys_id: sysId, sys_updated_on: gr.getValue("sys_updated_on"), advanced: getBool(gr, "advanced"), match_all: getBool(gr, "match_all"), }); } } function loadUsers(ids, offset, limit) { var found = []; if (ids.length > 0) { var present = {}; var chunks = chunk(ids, SYS_ID_IN_CHUNK); var c; for (c = 0; c < chunks.length; c++) { var gr = new GlideRecord("sys_user"); gr.addQuery("sys_id", "IN", chunks[c].join(",")); gr.addActiveQuery(); gr.query(); while (gr.next()) { present[gr.getUniqueValue()] = true; } } var unresolved = []; var j; for (j = 0; j < ids.length; j++) { if (present[ids[j]]) { found.push(ids[j]); } else { unresolved.push(ids[j]); } } return { found: found, unresolved: unresolved }; } var pager = new GlideRecord("sys_user"); pager.addActiveQuery(); pager.orderBy("sys_id"); pager.chooseWindow(offset, offset + limit, true); pager.query(); while (pager.next() && found.length < limit) { found.push(pager.getUniqueValue()); } return { found: found, unresolved: [] }; } function evaluate(userSysId, criteriaIds) { if (criteriaIds.length === 0) { return []; } var result = sn_uc.UserCriteriaLoader.getMatchingCriteria( userSysId, criteriaIds ); return normalizeIdArray(result); } function respondMatchingUsers( res, requestedCriteria, memberOffset, memberLimit ) { if (requestedCriteria.length === 0) { return respondError( res, 400, "invalid_request", "criteria_sys_ids is required for matching_users mode." ); } if (requestedCriteria.length > MAX_CRITERIA_PER_MATCHING_USERS_REQUEST) { return respondError( res, 400, "too_many_criteria", "criteria_sys_ids exceeds " + MAX_CRITERIA_PER_MATCHING_USERS_REQUEST + " for matching_users mode; chunk the request." ); } var readableTables = {}; if ( callerDomainMasksReads() || !tableHasReadableRows("user_criteria", readableTables) ) { return respondJson(res, 200, { serval_acl_version: SERVAL_ACL_VERSION, mode: "matching_users", criteria: [], criteria_members: {}, skipped_advanced_criteria_sys_ids: [], conditionless_criteria_sys_ids: [], errored_criteria_sys_ids: requestedCriteria, }); } var criteria = loadCriteriaConditions(requestedCriteria); var meta = []; var criteriaMembers = {}; var skippedAdvanced = []; var conditionless = []; var errored = []; var i; for (i = 0; i < criteria.length; i++) { var crit = criteria[i]; meta.push(crit.meta); if (crit.advanced) { skippedAdvanced.push(crit.sysId); continue; } // No readable condition value is NOT "everyone". A field-level ACL on // user_criteria masks company/department/location to "" for this // account, and that row reads exactly like the vanilla "Any User" // record; computing it here widened 24 country criteria to a whole // population once. Only the native evaluator (per-user mode) can tell // the two apart, so the criteria is handed back for that, and listed // as errored so a pre-1.2 caller retains last-known-good instead. if (crit.conditions.length === 0) { conditionless.push(crit.sysId); errored.push(crit.sysId); continue; } try { if (!criteriaDimensionsReadable(crit, readableTables)) { errored.push(crit.sysId); continue; } criteriaMembers[crit.sysId] = pageMembers( computeCriteriaMembers(crit), memberOffset, memberLimit ); } catch (e) { errored.push(crit.sysId); } } return respondJson(res, 200, { serval_acl_version: SERVAL_ACL_VERSION, mode: "matching_users", criteria: meta, criteria_members: criteriaMembers, skipped_advanced_criteria_sys_ids: skippedAdvanced, conditionless_criteria_sys_ids: conditionless, errored_criteria_sys_ids: errored, }); } function conditionDimensions() { return [ { field: "user", kind: "user" }, { field: "group", kind: "group" }, { field: "role", kind: "role" }, { field: "company", kind: "sys_user_field" }, { field: "department", kind: "sys_user_field" }, { field: "location", kind: "sys_user_field" }, { field: "cost_center", kind: "sys_user_field" }, ]; } function loadCriteriaConditions(ids) { var out = []; var chunks = chunk(ids, SYS_ID_IN_CHUNK); var c; for (c = 0; c < chunks.length; c++) { var gr = new GlideRecord("user_criteria"); gr.addQuery("sys_id", "IN", chunks[c].join(",")); gr.addActiveQuery(); gr.query(); while (gr.next()) { var sysId = gr.getUniqueValue(); out.push({ sysId: sysId, advanced: getBool(gr, "advanced"), matchAll: getBool(gr, "match_all"), conditions: readConditions(gr), meta: { sys_id: sysId, sys_updated_on: gr.getValue("sys_updated_on"), advanced: getBool(gr, "advanced"), match_all: getBool(gr, "match_all"), }, }); } } return out; } function readConditions(gr) { var conditions = []; var dims = conditionDimensions(); var d; for (d = 0; d < dims.length; d++) { var spec = dims[d]; var ids = splitIds("" + (gr.getValue(spec.field) || ""), []); if (ids.length > 0) { conditions.push({ field: spec.field, kind: spec.kind, ids: ids }); } } return conditions; } function conditionTables(condition) { if (condition.kind === "group") { return ["sys_user_grmember", "sys_user_group"]; } if (condition.kind === "role") { return ["sys_user_has_role"]; } return ["sys_user"]; } function criteriaDimensionsReadable(crit, cache) { if (!tableHasReadableRows("sys_user", cache)) { return false; } var i; for (i = 0; i < crit.conditions.length; i++) { var tables = conditionTables(crit.conditions[i]); var t; for (t = 0; t < tables.length; t++) { if (!tableHasReadableRows(tables[t], cache)) { return false; } } } return true; } function callerDomainMasksReads() { try { if (typeof gs === "undefined" || typeof gs.getSession !== "function") { return false; } var session = gs.getSession(); if (typeof session.getCurrentDomainID !== "function") { return false; } var domainID = "" + session.getCurrentDomainID(); return domainID !== "" && domainID !== "null" && domainID !== "global"; } catch (e) { return false; } } function tableHasReadableRows(table, cache) { if (cache[table] !== undefined) { return cache[table]; } var ok = false; try { var gr = new GlideRecord(table); gr.setLimit(1); gr.query(); ok = !!gr.next(); } catch (e) { ok = false; } cache[table] = ok; return ok; } function computeCriteriaMembers(crit) { if (crit.conditions.length === 0) { // Unreachable from respondMatchingUsers, which hands condition-less // criteria back before computing; kept as a guard so no caller can // turn "no readable conditions" into every active user. return []; } var combined = null; var i; for (i = 0; i < crit.conditions.length; i++) { var fieldUsers = resolveFieldUsers(crit.conditions[i]); if (combined === null) { combined = fieldUsers; } else if (crit.matchAll) { combined = intersectSets(combined, fieldUsers); if (setIsEmpty(combined)) { return []; } } else { combined = unionInto(combined, fieldUsers); } } var members = setToSortedArray(combined); if (needsActiveUserFilter(crit)) { members = filterActiveUsers(members); } return members; } function resolveFieldUsers(condition) { var set = {}; var i; if (condition.kind === "user") { for (i = 0; i < condition.ids.length; i++) { set[condition.ids[i]] = true; } return set; } if (condition.kind === "group") { return collectMembership( "sys_user_grmember", "group", expandGroupDescendants(condition.ids), "user" ); } if (condition.kind === "role") { return collectMembership( "sys_user_has_role", "role", condition.ids, "user" ); } return collectActiveUsersByField(condition.field, condition.ids); } function expandGroupDescendants(groupIds) { var all = {}; var frontier = []; var i; for (i = 0; i < groupIds.length; i++) { all[groupIds[i]] = true; frontier.push(groupIds[i]); } var depth; for ( depth = 0; depth < MAX_GROUP_NESTING_DEPTH && frontier.length > 0; depth++ ) { var next = []; var chunks = chunk(frontier, SYS_ID_IN_CHUNK); var c; for (c = 0; c < chunks.length; c++) { var gr = new GlideRecord("sys_user_group"); gr.addQuery("parent", "IN", chunks[c].join(",")); gr.query(); while (gr.next()) { var id = gr.getUniqueValue(); if (!all[id]) { all[id] = true; next.push(id); } } } frontier = next; } return setToSortedArray(all); } function collectMembership(table, queryField, queryValues, userField) { var set = {}; var chunks = chunk(queryValues, SYS_ID_IN_CHUNK); var c; for (c = 0; c < chunks.length; c++) { var gr = new GlideRecord(table); gr.addQuery(queryField, "IN", chunks[c].join(",")); gr.query(); while (gr.next()) { var v = gr.getValue(userField); if (v) { set["" + v] = true; } } } return set; } function collectActiveUsersByField(field, values) { var set = {}; var chunks = chunk(values, SYS_ID_IN_CHUNK); var c; for (c = 0; c < chunks.length; c++) { var gr = new GlideRecord("sys_user"); gr.addActiveQuery(); gr.addQuery(field, "IN", chunks[c].join(",")); gr.query(); while (gr.next()) { set[gr.getUniqueValue()] = true; } } return set; } function needsActiveUserFilter(crit) { var hasMembership = false; var hasUserField = false; var i; for (i = 0; i < crit.conditions.length; i++) { if (crit.conditions[i].kind === "sys_user_field") { hasUserField = true; } else { hasMembership = true; } } if (crit.matchAll) { return !hasUserField; } return hasMembership; } function filterActiveUsers(candidateIds) { var out = []; var chunks = chunk(candidateIds, SYS_ID_IN_CHUNK); var c; for (c = 0; c < chunks.length; c++) { var gr = new GlideRecord("sys_user"); gr.addQuery("sys_id", "IN", chunks[c].join(",")); gr.addActiveQuery(); gr.query(); while (gr.next()) { out.push(gr.getUniqueValue()); } } out.sort(); return out; } function unionInto(target, source) { var id; for (id in source) { if (source.hasOwnProperty(id)) { target[id] = true; } } return target; } function intersectSets(a, b) { var out = {}; var id; for (id in a) { if (a.hasOwnProperty(id) && b[id]) { out[id] = true; } } return out; } function setIsEmpty(set) { var id; for (id in set) { if (set.hasOwnProperty(id)) { return false; } } return true; } function setToSortedArray(set) { var out = []; var id; for (id in set) { if (set.hasOwnProperty(id)) { out.push(id); } } out.sort(); return out; } function pageMembers(members, offset, limit) { var page = members.slice(offset, offset + limit); return { member_sys_ids: page, total: members.length, truncated: offset + page.length < members.length, }; } function isArray(value) { return Object.prototype.toString.call(value) === "[object Array]"; } function isOptionalArray(value) { return value === undefined || value === null || isArray(value); } function toStringSet(value) { var out = []; var seen = {}; if (!isArray(value)) { return out; } var i; for (i = 0; i < value.length; i++) { var s = ("" + value[i]).trim(); if (s && !seen[s]) { seen[s] = true; out.push(s); } } return out; } function normalizeIdArray(value) { var out = []; if (value === null || value === undefined) { return out; } var i; if (typeof value === "string") { return splitIds(value, out); } if (typeof value.size === "function" && typeof value.get === "function") { var n = value.size(); for (i = 0; i < n; i++) { pushId(out, value.get(i)); } return out; } if (typeof value.length === "number") { for (i = 0; i < value.length; i++) { pushId(out, value[i]); } return out; } return splitIds("" + value, out); } function splitIds(str, out) { var parts = str.split(","); var i; for (i = 0; i < parts.length; i++) { pushId(out, parts[i]); } return out; } function pushId(out, raw) { var s = ("" + raw).trim(); if (s) { out.push(s); } } function chunk(arr, size) { var chunks = []; var i; for (i = 0; i < arr.length; i += size) { chunks.push(arr.slice(i, i + size)); } return chunks; } function getBool(gr, field) { var v = gr.getValue(field); return v === "1" || v === "true"; } function toNonNegativeInt(value, fallback) { var n = parseInt(value, 10); if (isNaN(n) || n < 0) { return fallback; } return n; } function toBoundedInt(value, fallback, max) { var n = parseInt(value, 10); if (isNaN(n) || n <= 0 || n > max) { return fallback; } return n; } function respondJson(res, status, obj) { res.setStatus(status); res.setContentType("application/json"); res.getStreamWriter().writeString(JSON.stringify(obj)); } function respondError(res, status, code, message) { respondJson(res, status, { serval_acl_version: SERVAL_ACL_VERSION, error: { code: code, message: message }, }); } })(request, response); ``` Paste the script **verbatim** and don't let an editor reformat it. It must stay ES5 / Rhino-parseable - a trailing comma before a closing parenthesis is a fatal parse error at install time on ServiceNow's Rhino engine. **Upgrading from an earlier install** is the same operation: paste the current script over the resource's existing **Script** field and save. The upgrade is backwards-compatible and takes effect immediately - the running Serval sync is unaffected mid-upgrade. ### Restrict the endpoint to the Serval service account Create an ACL on the resource operation so **only** the Serval service account can call it. Restrict the REST endpoint (the `sys_ws_operation` ACL) to the role you assigned to your Serval integration user in [Get your credentials](#get-your-credentials). Creating or editing a Scripted REST **operation ACL** requires elevating to the **security\_admin** role (top-right user menu → **Elevate role**). A plain admin can't save the ACL, and **the failure is quiet** - the save appears to succeed but the ACL isn't stored. Elevate first, then create the ACL. ### Copy the API namespace into Serval Open the **Scripted REST API** form (**System Web Services → Scripted REST APIs → Serval ACL**) and read the **API namespace** value ServiceNow assigned. On a global-scope install this is your instance's global namespace - typically your bare instance number (for example `2191009`) or a value like `x_1234567_serval`, **not** `x_serval`. The endpoint's full route is `POST /api//serval_acl/matching_criteria`. Copy that namespace, then in Serval open **Integrations → All integrations → ServiceNow → Connect** (or edit the existing connection) and paste it into the **ACL Endpoint API Namespace** field. ServiceNow Scripted REST API form showing the API namespace value alongside the ACL Endpoint API Namespace field on the Serval ServiceNow connection screen ### Verify Call the endpoint as the Serval service account with a known user and criterion: ```bash theme={null} curl -sS -u "$SERVAL_SVC_USER:$SERVAL_SVC_PASS" \ -X POST "https://.service-now.com/api//serval_acl/matching_criteria" \ -H 'Content-Type: application/json' \ -d '{"user_sys_ids":[""],"criteria_sys_ids":[""]}' ``` Expect a `200` whose body carries a `serval_acl_version` and a `matches` map. `matches[""]` contains `` exactly when that user matches that criterion in the native Knowledge portal. A `400` reading *"Requested URI does not represent any resource"* means the namespace or API ID is wrong, or the resource isn't installed - recheck the steps above and the namespace you gave Serval. Then verify the bulk evaluation mode Serval's sync uses on large instances: ```bash theme={null} curl -sS -u "$SERVAL_SVC_USER:$SERVAL_SVC_PASS" \ -X POST "https://.service-now.com/api//serval_acl/matching_criteria" \ -H 'Content-Type: application/json' \ -d '{"mode":"matching_users","criteria_sys_ids":[""]}' ``` Expect a `200` echoing `"mode": "matching_users"` whose `criteria_members[""]` lists the users that criterion matches. A response without the `mode` echo means the pasted script is an earlier version - re-paste the script above. In Serval, article visibility reflects the newly evaluated criteria **after the next knowledge sync completes**: articles that were hidden because they were gated by script-based criteria become answerable for the users ServiceNow says can read them. ### Limitation: caller-scoped criteria scripts ServiceNow evaluates advanced (script) criteria **as the calling account** - here, the Serval service account - not as the user being checked. A criterion whose script calls `gs.getUserID()`, `gs.getUser()`, `gs.getUserName()`, `gs.hasRole()`, `gs.getSession()`, or other session-state functions therefore returns an answer about the service account, not the target user. Serval trusts ServiceNow's result for knowledge-article and catalog permissions, which can grant or deny access differently than intended. The fix is on the ServiceNow side: rewrite such criteria to test the `user_id` the evaluator passes in, instead of the current-session caller - this is ServiceNow's own recommendation. Once rewritten, the endpoint evaluates them correctly per user and the affected articles become answerable. This is the one customer-side action item on this page. *** ## Live agent handoff via VA Bot-to-Bot (optional) Serval can hand a conversation off to a human ServiceNow agent mid-flow, then bridge the agent's replies back into the Serval ticket so the user keeps chatting in their original surface (Slack, Teams, web, etc.). This rides on ServiceNow's native **Virtual Agent Bot-to-Bot** APIs. The handoff itself doesn't require a Serval-shipped update set or a Scripted REST API. Setup on the ServiceNow side is roughly: install the Virtual Agent API plugin (if not already installed), grant the Serval service account a few additional permissions, create a Token Verification + Message Auth + Provider Application + Outbound REST Message pointing at a Serval-hosted webhook URL, and (optionally) tune the AWA routing for the chat channel you want to use for the handoff. Install a read-only Scripted REST API only if the Serval workflow must check availability for a route that depends on skills, country, language, or other customer-specific rules before it starts the handoff. Live agent sessions appear on Serval tickets as an additional external ticket with `subtype = "interaction"` on the existing ServiceNow integration - they do **not** create a separate integration or channel type. The auto-created `interaction` record on the ServiceNow side is the same record type ServiceNow uses for all VA-mediated chats. ### How the bridge works The bridge has three legs: 1. **Inbound to ServiceNow** - Serval opens, sends messages on, and ends a Bot-to-Bot conversation by calling ServiceNow's Virtual Agent Bot Integration endpoint (installed by the Virtual Agent API plugin). The action discriminator travels in the request body: `START_CONVERSATION`, `AGENT_CHAT`, or `END_CONVERSATION`. 2. **Outbound from ServiceNow** - when the live agent types a reply, ServiceNow's Provider Application looks up its associated Outbound REST Message and POSTs the response to the URL you configured there. That URL is the Serval-hosted webhook. 3. **Availability pre-flight (optional)** - for simple channel routing, Serval can read the `awa_agent_presence_capacity` table to check whether any agents are online. For customer-specific routing, Serval can send the intended route to a read-only evaluator on the ServiceNow instance. Routing (which queue / which agent the conversation lands in) is handled entirely by AWA on the ServiceNow side. The two knobs you have from Serval workflow code are: * **`channelId`** on the start action - maps to a ServiceNow `sys_cs_channel` record. Defaults to `"chat"`. The channel record's "Bot to Bot Synchronous" flag and its AWA queue assignment together determine where the conversation routes. * **`contextVariables`** on the start action - a free-form key/value bag passed to ServiceNow on every turn. Customers configure their AWA routing rule against the variable name(s) of their choice (e.g. `u_liveagent_optional_skills`). See [Customize routing with context variables](#step-5-customize-routing-with-context-variables) below. ### Prerequisites * **Virtual Agent** + **Virtual Agent API** plugins installed on your ServiceNow instance (Quebec or later). * The Serval ServiceNow integration must already be connected (everything above on this page). * **Now Assist Pro** licensing is not required - Bot-to-Bot is part of the base Virtual Agent API plugin. ### Limitations (read before you commit) * **Closing a Serval ticket does not automatically end the ServiceNow conversation.** Your workflow should call the end-session action when the ticket resolves if you want symmetric cleanup. The conversation eventually times out on the ServiceNow side either way. * **Agent attribution is automatic; assignment details are not.** ServiceNow's Bot-to-Bot payloads carry per-message agent information, and Serval resolves it to the ServiceNow user - so agent replies are attributed correctly on the Serval ticket with no extra work. What the asynchronous START acknowledgment does *not* tell you is which queue the conversation landed in or when an agent picked up; poll the auto-created `interaction` record's `assigned_to` field from a workflow if you need that - see the example workflow below. * **Inbound auth verification is currently advisory.** The Basic-auth password on inbound webhooks is forwarded onto the event for downstream verification, but the constant-time check against the rotated token is not yet enforced server-side. The per-install webhook URL contains an unguessable UUID, which is the practical access control today. Treat the rotated token as a not-yet-load-bearing secret in the meantime - full server-side verification is on the roadmap. * **Attachments require trusted-media-domain configuration.** Files do cross the bridge in both directions, but ServiceNow refuses to download attachments from URLs whose host isn't listed under the active Provider Application record's *Trusted media domains* (the `sys_cs_provider_application` record - labeled **Provider Channel Identity** on some releases). You must add Serval's S3 attachment host (the host of the presigned URL Serval sends for attachments - visible on a test egress) to that list, otherwise the live agent will see *"We couldn't download your file using the specified URL"* instead of the image. See the ServiceNow docs: [Set up trusted media domains for secure file upload](https://www.servicenow.com/docs/r/yokohama/conversational-interfaces/virtual-agent/ccif-secure-file-upload.html) for the field and ACL setup. * **Word and Excel uploads require interaction enrichment.** ServiceNow's Bot-to-Bot endpoint rejects modern Office MIME types, so Serval uploads them to the backing `interaction` record instead. Include the post-START interaction poll and `attachInteractionSysIdToLiveAgentSession` step below when these file types must be supported. An upload that races that enrichment is deferred and retried after the sys\_id is stored. ### What agent replies look like on the Serval ticket Three kinds of inbound items surface on the bridged ticket; everything else (topic pickers and other Virtual Agent scaffolding) is accepted and dropped: * **Agent text** surfaces as a comment, attributed to the ServiceNow agent. * **Agent images and files** from ServiceNow's conversational media and attachment endpoints surface as attachments. Generic `OutputLink` redirects remain text links and are never downloaded. Downloads use your stored integration credentials, do not follow redirects, and are capped at 50 MB per file. If a download fails, Serval posts the placeholder comment `[attachment could not be downloaded - please refresh ServiceNow Agent Workspace]` instead of failing the whole message. * **System prompts** (such as AWA idle-timeout warnings) surface as comments so the user can reply and keep the chat alive. When the conversation ends - whether the agent closes it or it times out - Virtual Agent's closing lifecycle text (such as "no agents available" or "the conversation has ended" boilerplate) is suppressed so it doesn't clutter the ticket. A real agent's final message **is** preserved and lands before the channel disconnects; afterwards Serval posts a single "Live agent chat session has ended." note. Duplicate webhook deliveries are deduplicated automatically. ### Step 1: Grant additional permissions to the Serval service account The standard Serval ACLs cover the Table API surface used by the rest of the integration. Live Agent needs two additional ServiceNow roles plus reads on the AWA tables and the `interaction` table. Add these to your Serval service-account user: **Roles:** | Role | Why | | - | - | | `virtual_agent_admin` | Required for ServiceNow's Bot Integration endpoint to accept Serval's Bot-to-Bot calls. | | `interaction_agent` | Lets Serval read the auto-created `interaction` record after `START_CONVERSATION` (for the optional assignment poll) and lets the inbound attachment-download path resolve the agent-supplied conversational-media URLs on image items. | **Table reads (one ACL per table, `Type: record`, `Operation: read`, `Requires role: x_serval_integration` or whichever role you assigned to the Serval service account):** | Table | Purpose | | - | - | | `awa_agent_presence_capacity` | Used by the availability check. Without this, the check will report no agents available for everyone. | | `awa_agent_presence` | Used by AWA routing - `presence_capacity` is a view that joins this in. | | `awa_agent_capacity` | Same; joined by the `presence_capacity` view. | | `interaction` | Read access for the optional `assigned_to` poll. Already covered if you're using the `interaction_agent` role above. | ### Step 2: Generate the shared bot token in Serval In your Serval workspace, navigate to **Integrations → ServiceNow → Ticket Syncing**. Scroll to the **Live Agent (VA Bot-to-Bot)** section and click **Generate token**. You'll see three values you'll need in the next step: | Value | What it is | | - | - | | **Inbound Webhook URL** | Serval-hosted URL the ServiceNow Outbound REST Message will POST agent replies to. Per-install - contains an unguessable UUID - so do not share between environments. | | **Authentication Username** | `serval` by convention. Any username is accepted - the password (the token below) is the authenticator, and it must be non-empty. | | **Authentication Token** | One-time-displayed opaque secret - **copy it now**, you cannot view it again. Click **Rotate token** later if you ever need a new one (rotation invalidates the previous value immediately). | **One token, two destinations on the ServiceNow side.** This token value lives in two places on ServiceNow: * The **Token Verification** record. Serval injects this value into the body of every Bot-to-Bot call; ServiceNow's Message Auth middleware verifies it before processing. * The **Outbound REST Message** Basic-auth password. ServiceNow presents this value when posting agent replies to the Inbound Webhook URL above. You'll wire both up in the next step. ### Step 3: Configure the four ServiceNow records that wire up Bot-to-Bot ServiceNow's Bot-to-Bot setup links four records together. The record names below are the OOB tables - the navigation labels may vary slightly by release. Navigate to **System Web Services → Scripted Web Services → Scripted REST APIs** and open the **VA Bot Integration** record. Open the **Bot Integration** resource. On the **Security** tab, set **Requires authentication = true** and **Requires ACL authorization = false**. Save. This makes the bot integration endpoint reject anonymous calls - the Token Verification record you'll create next is what gates it. In the filter navigator, type `token_verification.list` and press Enter. Click **New**. Fill in: | Field | Value | | - | - | | **Name** | `Serval` (or any human-readable name) | | **Token** | The Authentication Token from Serval (from Step 2) | Save. This is the value ServiceNow will validate on every inbound call from Serval. In the filter navigator, type `message_auth.list` and press Enter. Click **New**. Fill in: | Field | Value | | - | - | | **Name** | `Serval Bot Auth` | | **Provider** | `Serval` (free-text; only used for organization) | | **Inbound Message Verification** | Pick the Token Verification record from the previous step (`Serval`) | | **Outbound Message Creation** | Pick the same Token Verification record | Save. In the filter navigator, type `sys_cs_provider_application.list` and press Enter. Click **New**. Fill in: | Field | Value | | - | - | | **Name** | `Serval Bot` | | **Inbound ID** | `serval` (or any unique slug - this is the `appInboundId` value, only needed in multi-bot instances; single-bot instances can pick any value) | | **Message Auth** | Pick the Message Auth record from the previous step (`Serval Bot Auth`) | | **Provider** | `VA Bot to Bot Provider` | Save. The name of this record matters for the next step. This is also the record that carries the **Trusted media domains** list used for attachment egress (see Limitations above). In the Provider Identity Properties related list, create a Custom Adapter Property with **Name** `third_party_chat` and **Value** `true`. On Virtual Agent API v4 or later, this makes ServiceNow store Serval's `clientSessionId` on the Interaction record and include the Interaction `sys_id` as `interactionId` in callback payloads. Without it, cross-system reporting cannot reliably join the two records. In the filter navigator, type `REST Message` and open the table. Click **New**. Fill in: | Field | Value | | - | - | | **Name** | **Must exactly match the Provider Application name from the previous step** (`Serval Bot`). ServiceNow finds the outbound endpoint by name lookup against the active Provider Application. | | **Endpoint** | The Inbound Webhook URL from Serval (Step 2). | | **Authentication type** | `Basic` | | **Use mutual authentication** | unchecked | | **Basic auth profile** | Create a new Basic Auth profile (or pick an existing one) with `Username: serval` and the Authentication Token from Step 2 as the password. | Save. ServiceNow will now use this REST Message - looked up by name - whenever the Provider Application emits an agent reply. By convention, also create a single HTTP Method record on the REST Message named `post` with: | Field | Value | | - | - | | **HTTP method** | `POST` | | **Endpoint** | Same as the parent REST Message | | **HTTP Headers** | `Content-Type: application/json` | Some ServiceNow releases auto-create this from the parent record; if your release does, you can skip the explicit creation. In the filter navigator, type `sys_cs_channel.list` and press Enter. Find the channel you intend to route through (the OOB one is named `chat` - its sys\_id is what you'll pass as `channelId` from your workflows; the literal string `"chat"` also works on most releases). On the channel record, confirm **Bot to Bot Synchronous = true**. If it's not, set it and save. Without this flag, the bot integration endpoint will reject `START_CONVERSATION` calls with a routing error. If you ever click **Rotate token** in Serval, you must update **both** ServiceNow records: 1. The Token Verification record's `Token` field. 2. The Basic Auth profile used by the Outbound REST Message (or, if you embedded the password directly on the REST Message, update it there). Serval-to-ServiceNow calls (starting sessions, sending messages, ending conversations) fail until the Token Verification record matches the new token - ServiceNow checks it on every call. Inbound agent messages keep flowing in the meantime because Serval's inbound verification is currently advisory (see [Limitations](#limitations-read-before-you-commit) above), but update the Basic Auth profile anyway so the inbound direction does not break once server-side verification is enforced. ### Step 4: SDK building blocks The ServiceNow SDK exposes six thin building-block actions for live agent. They are intentionally **not orchestration helpers** - live-agent flows vary enough between customer ServiceNow configurations (different chat experiences, custom AWA routing rules, renamed topics, varying trigger phrases for NLU) that workflow authors compose these directly rather than configure a single high-level wrapper: * **`checkLiveAgentAvailability`** - channel-level pre-flight: are any human agents online right now? Reads the agent-presence capacity table and returns whether agents are available plus a queue-depth figure (the sum of agents' remaining capacity). Use this when the channel is sufficient to identify the agent pool. * **`checkLiveAgentRouteAvailability`** - route-level pre-flight: sends the user, message, channel, context variables, and provider application to a customer-installed, read-only ServiceNow evaluator. Use this when agents share a channel but AWA routes by skills, country, language, or other customer-specific rules. * **`startLiveAgentSession`** - opens a conversation. The caller supplies the Serval `ticketId`, the user (a ServiceNow `sys_user` sys\_id is preferred, plus email), the verbatim `message` text (including any NLU trigger phrase), `channelId` (defaults to `"chat"`), `contextVariables` for routing (re-sent on every turn), and optionally `appInboundId` for multi-bot instances. `connectTicket` defaults to true, which wires the ServiceNow conversation onto the Serval ticket as an `interaction`-subtype external ticket so user replies auto-egress as `AGENT_CHAT` turns. It returns the session identifiers - including `clientSessionId` and a `liveAgentData` blob that the attach action below consumes. * **`sendLiveAgentMessage`** - manually sends an `AGENT_CHAT` turn. Usually **not** needed: once the ticket is connected, user replies auto-egress through the standard pipeline. Use it for programmatic messages (auto-replies, scripted status updates, testing). * **`endLiveAgentSession`** - force-ends a session (e.g. on ticket resolve, user abandon, or SLA timeout). * **`attachInteractionSysIdToLiveAgentSession`** - manually stashes a polled `interaction` sys\_id when an older ServiceNow Virtual Agent API callback does not include `interactionId`. Virtual Agent API v4 callbacks are captured automatically. ### Step 5: Customize routing with context variables `contextVariables` is the principal knob for AWA routing. The variable names you pass are **customer-specific** - they must match the conditions on whichever AWA routing rule you've configured on your ServiceNow instance. For example, an "IT Live Agent Chat" queue whose routing rule has the condition `context.u_liveagent_optional_skills = IT` is targeted by passing a `u_liveagent_optional_skills` context variable with the value `IT`. Other instances might use `u_skill_required`, `routing_skill`, or any other custom variable name. To find the right variable name on your instance, check your AWA routing rule's condition script, or ask your ServiceNow admin. Custom interaction-record fields (e.g. CMDB tag, custom assignment-group overrides, region routing) can also be projected onto the auto-created `interaction` record via a ServiceNow-side Business Rule that reads the `contextVariables` payload. This is a pure ServiceNow-side customization - no Serval changes required. #### Check availability for the exact route ServiceNow doesn't provide a documented, read-only API that previews the result of arbitrary AWA routing rules. If a workflow must hide the live-agent option unless an agent matches the exact route, create a read-only Scripted REST API resource on the ServiceNow instance. The resource owns the customer-specific evaluation and exposes a stable contract to Serval. Configure the resource to accept this request body: ```json theme={null} { "user": { "userId": "", "email": "user@example.com" }, "message": "I need help with my laptop", "channelId": "chat", "contextVariables": { "requested_skill": "IT", "requester_country": "US" }, "appInboundId": "serval" } ``` The resource must return either the result directly or under ServiceNow's standard `result` envelope: ```json theme={null} { "result": { "agentsAvailable": false, "queueDepth": 0, "reason": "No agents matching this route are available." } } ``` `agentsAvailable` is required. `queueDepth` and `reason` are optional. Require authentication on the resource and authorize only the Serval service account or its dedicated role. The resource must only inspect routing and capacity; it must not create an AWA work item, interaction, or conversation. Build the route once in the Serval workflow and pass the same values to the availability and start actions: ```ts theme={null} const route = { user: { userId: userSysId, email: args.email }, message: args.userMessage, channelId: "chat", contextVariables: { requested_skill: args.requestedSkill, requester_country: args.requesterCountry, }, }; const availability = await servicenow.checkLiveAgentRouteAvailability( { endpointPath: "/api//live_agent/route_availability", ...route, }, ctx, ); if (!availability.agentsAvailable) { return { available: false, reason: availability.reason ?? "No matching live agents are available.", queueDepth: availability.queueDepth, }; } await servicenow.startLiveAgentSession( { ticketId: args.ticketId, ...route }, ctx, ); ``` Because the evaluator receives the same route as `startLiveAgentSession`, the ServiceNow administrator can change the local routing model without adding customer-specific parameters to the Serval SDK. Update the evaluator and AWA rules together whenever the ServiceNow routing inputs change. ### Step 6: Example workflow - START\_CONVERSATION with routing and assignment poll This mirrors the canonical pattern verified end-to-end against a real ServiceNow instance. You can drop this into a Serval workflow as a starting point and adapt the routing skills, trigger phrase, and message composition to your environment. ```ts theme={null} import { workflow, sleep } from "serval/core"; import * as servicenow from "serval/integrations/servicenow"; export const main = workflow({ fn: async function ( args: { email: string; // The end-user's email userMessage: string; // The user's natural-language message ticketId: string; // The Serval ticket to bridge onto }, ctx: servicenow.context.ServiceNowIntegration, ) { // 1) Resolve the ServiceNow sys_user.sys_id for this user. The // Bot-to-Bot endpoint accepts email/username but account-linking // works best with a sys_id, and AWA assignment is more reliable. const userSysId = await servicenow.lookupUserSysIdByEmail( { email: args.email }, ctx, ); // 2) Compose the message text. The trailing trigger phrase is what // ServiceNow's NLU classifies as the "Live Agent Support" topic - // the OOB topic that drives the AWA handoff without going through // the Greetings picker. Customers who have renamed that topic // or have a custom topic should adapt the phrase to match. const ROUTING_TRIGGER_PHRASE = "I need a live agent. Please connect me with Live Agent Support - I want to talk to an agent."; const message = args.userMessage && args.userMessage.length > 0 ? args.userMessage + "\n\n" + ROUTING_TRIGGER_PHRASE : ROUTING_TRIGGER_PHRASE; // 3) Open the conversation. `connectTicket: true` (default) wires // the ServiceNow clientSessionId onto the Serval ticket as an // interaction-subtype external ticket, so subsequent user // replies on the Serval ticket auto-egress as AGENT_CHAT turns. const { clientSessionId, liveAgentData } = await servicenow.startLiveAgentSession( { ticketId: args.ticketId, user: { userId: userSysId, email: args.email }, message, channelId: "chat", contextVariables: { u_liveagent_optional_skills: "IT" }, }, ctx, ); // 4) Optional: poll the `interaction` table to learn which agent // actually picked up the conversation. START returns only an // async ack - the real assignment happens a moment later when // AWA matches an available agent. Stop early once `assigned_to` // is populated. let routingInteraction: Record | null = null; for (let attempt = 0; attempt < 4; attempt++) { await sleep({ durationMs: 3000 }); const { result } = await servicenow.tableApiRequest( { method: "GET", path: "/api/now/table/{tableName}", pathParams: { tableName: "interaction" }, query: { sysparm_query: "opened_for=" + userSysId + "^type=chat^ORDERBYDESCsys_created_on", sysparm_fields: "sys_id,number,state,assigned_to,assignment_group,queue,opened_at", sysparm_display_value: "true", sysparm_exclude_reference_link: "true", sysparm_limit: "1", }, }, ctx, ) as { result: Array> }; if (result.length > 0) { routingInteraction = result[0]; if (routingInteraction["assigned_to"]) { break; // Agent picked up - done polling. } } } // 5) Stash the polled `interaction.sys_id` onto the Serval external // ticket. This enables the Agent Workspace deep link and the // record-upload fallback for Word and Excel files. It can be // omitted only if those capabilities are not needed. if (routingInteraction && typeof routingInteraction["sys_id"] === "string") { await servicenow.attachInteractionSysIdToLiveAgentSession( { ticketId: args.ticketId, clientSessionId, liveAgentData, interactionSysId: routingInteraction["sys_id"], }, ctx, ); } return { clientSessionId, assignedAgent: routingInteraction?.["assigned_to"] ?? null, assignmentGroup: routingInteraction?.["assignment_group"] ?? null, }; }, }); ``` While the session is active: * **User → agent**: any new message the user sends in their original surface fans out to the ServiceNow agent automatically as an `AGENT_CHAT` turn - no extra workflow code required; Serval's ticket-channel egress handles it. * **Agent → user**: ServiceNow's Outbound REST Message posts the agent's typed reply to the Inbound Webhook URL configured in Step 3. Serval ingresses it as a comment on the bridged ticket (attributed to the agent), which surfaces back in the user's original surface. ### Step 7: Optionally end the session symmetrically When the Serval ticket auto-resolves or the user abandons, call `endLiveAgentSession` with the `clientSessionId` saved from the START workflow output, the same user, a short `reason` such as `ticket_resolved`, and the same `channelId` (and `contextVariables`, if your routing rule expects them on every turn). This is best-effort - the ServiceNow side eventually times the conversation out either way, but an explicit `END_CONVERSATION` cleans up the `interaction` record faster and gives the agent a clean "user ended chat" signal. ### Step 8: Real-time translation (optional) Live agents and end users frequently speak different languages - a Spanish-speaking employee opens a chat in Slack, the routed IT queue is staffed by English-speaking agents, and you want both sides to read their own language without the agent having to copy/paste into a translation tool. To enable **bidirectional real-time translation** for the lifetime of a conversation, pass two extra fields on `startLiveAgentSession`: `userLanguage` (a BCP-47 code for the requester, e.g. `es`) and `agentLanguage` (the code your live agents read and write, e.g. `en`). What changes after that: * **User → agent.** Every message the user types on the upstream surface is translated from `userLanguage` into `agentLanguage` before it lands as an `AGENT_CHAT` turn on ServiceNow. * **Agent → user.** Every reply the live agent posts is translated from `agentLanguage` into `userLanguage` before it's persisted on the Serval ticket and fanned back out to the user's surface. Behavior worth knowing: * Both fields must be set. If either is omitted, or both share a primary subtag (e.g. `en` vs `en-US`), the conversation runs through verbatim - no translation is attempted. * URLs, code blocks, ticket numbers, and @mentions are preserved verbatim across the translation. * Translation failures fall back to the original text and log a warning. A passthrough turn is strictly better than a dropped turn on a live chat - the agent or user can ask the other side to rephrase. * Translation is handled by Serval automatically - there is nothing to configure on the ServiceNow side. Detecting the requester's language automatically (e.g. from the user's Serval profile locale, or from the first inbound message) is up to the workflow author - pass whatever you've resolved into `userLanguage`. If `userLanguage` is unknown, no translation is attempted in either direction. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your ServiceNow integration - including custom routing-rule design, multi-bot Provider Application setups, interaction-field Business Rules, and real-time translation rollouts. # Sigil Source: https://docs.serval.com/sections/integrations/sigil Manage Sigil users, groups, and application access from Serval workflows. ## Connect Sigil Open [Sigil Platform](https://sigil.app/admin/platform/) and sign in as an administrator. Open **Manage Credentials** and create a credential with the permissions your workflows need. Copy the secret when it is shown; Sigil displays it only once. Add the **Sigil** integration in Serval and enter the **API Credential Secret**. Run **Validate API connection**, followed by the health checks for the resources your workflows use. Serval stores the credential and injects it as a bearer token when calling `https://sigil.app/api`. Workflow code does not need the secret. The integration is marked Beta. ## Permissions The connection check calls `/api/users/me`, which requires authentication without additional permissions. Other health checks verify access separately: | Operation | Sigil permissions | | - | - | | Read users | Read Users | | Create, update, or delete users | Read Users and Add or Modify Users | | Read groups | Read Groups | | Create, update, or delete groups | Read Groups and Add or Modify Groups | | Read group memberships | Read Group Members | | Add or remove group memberships | Read Group Members and Add or Modify Group Members | | Read app configurations and effective access | Read Apps | Grant write permissions only when your workflows need them. A connection can pass authentication while a resource health check fails because its credential lacks permission. ## Workflow operations The **Sigil API request** action supports listing, creating, updating, and deleting users and groups; listing, adding, removing, and checking group membership; and reading apps and effective app access. To grant application access, read the app's `assignmentGroupId` and add the user to that group. To revoke a direct assignment, remove the matching membership. Nested groups can also grant access: inspect `/api/apps/access` and its `groupPath` before concluding that removing a direct membership removed all access. List endpoints use `limit` (maximum 1000), `offset`, and `total`. Increase `offset` by the number of returned records to read another page. Exact-match filters use `is:`; for example, `email: "is:person@example.com"` or `groupId: "is:"`. DELETE collection endpoints remove every matching record. Always supply filters identifying the intended user, group, or membership. An unfiltered DELETE can remove all records visible to the credential. For PATCH requests, omit fields you want to preserve. Sending `null` clears a nullable field. Creating users, groups, and memberships requires a Sigil `tenantId`; membership creation also requires `groupId` and the appropriate `memberUserId` or `memberGroupId`. This connector covers identity and application access. Device, session, audit-log, credential, token, tenant, and app-configuration administration are outside its current typed API. ## Rotate the credential Create a replacement credential in Sigil, update the connection secret in Serval, and run the health checks before revoking the old credential. Leaving the secret unchanged or blank when editing preserves the stored credential. A `401` indicates an invalid or expired credential. A `403` indicates a missing permission. The membership-check endpoint returns `404` when the user or group is not a member. # Sigma Computing Source: https://docs.serval.com/sections/integrations/sigma Connect Sigma Computing to Serval with API client credentials so workflows can call the full Sigma REST API on demand - workbooks, members, teams, connections, and more. ## About Sigma Computing Sigma Computing is a cloud business intelligence and analytics platform. Serval connects to your Sigma environment with an API client (a Client ID and Client Secret) created in Sigma's Developer Access, plus your regional API base URL. Once connected, Serval handles authentication entirely behind the scenes and workflows can call any part of Sigma's REST API on demand - roughly 120 endpoints, mostly API versions 2 and 2.1, covering workbooks, members, teams, connections, datasets, data models, workspaces, and governance. **Authentication:** OAuth 2.0 client credentials - a Sigma API client's Client ID and Client Secret, exchanged for access tokens that Serval obtains and refreshes automatically. There is no sign-in flow and no scopes to choose. **Data sync:** None. No background sync or ingestion starts when you connect - the integration is purely on-demand through workflows. ## What the Sigma Computing integration enables | Capability | Description | | - | - | | Full Sigma REST API access | Workflows use the "Sigma API request" action to call any of the roughly 120 typed endpoints in Sigma's REST API (versions 2 and 2.1, plus a few v3 alpha endpoints), generated from Sigma's official API specification. | | Workbook operations | List, export, copy, share, and manage workbooks, including pages, elements, embeds, schedules, materializations, bookmarks, version tags, lineage, and saving workbooks as templates. | | Member and team administration | Create, update, deactivate, and list members; manage teams and team membership; manage account types and their permissions. | | Data and governance | Manage connections and connection grants, datasets and materialization, data models and source swapping, workspaces and workspace grants, files and folders, grants, tags, templates, and shared templates. | | Row-level security | Manage user attributes and their team and user assignments to control row-level security. | | Multi-cloud, multi-region | A configurable API base URL covers Sigma deployments on AWS (US West, US East, Canada, Europe, UK, Australia), Azure (US, Europe, Canada, UK), and GCP. | Anything defined in the [Sigma REST API](https://help.sigmacomputing.com/reference/get-started-sigma-api) can be accessed through Serval. ## Get your credentials Serval needs a **Sigma API client** - a Client ID and Client Secret - created under **Administration > Developer Access**, plus the **API base URL** shown on that same page. Sigma's OAuth does not use scopes: the API client can do exactly what its owner's account type allows, so it should be owned by a user with the **Admin** account type if Serval will manage members, teams, account types, or governance. Sigma's official guides: [Sigma REST API - Get started](https://help.sigmacomputing.com/reference/get-started-sigma-api) and [Generate Sigma API client credentials](https://help.sigmacomputing.com/reference/generate-client-credentials). Log in to Sigma and click your profile icon in the top right, then open **Administration**. Select **Developer Access** from the left sidebar. Create a new API client (**Create New** / **Add Client**) and give it a descriptive name such as "Serval Integration". Copy both values. The Client Secret is shown **only once** - store it securely before closing the dialog. The Developer Access section also shows your **API base URL**. It depends on your cloud and region - for example aws-api.sigmacomputing.com (AWS US West), api.us-a.aws.sigmacomputing.com (AWS US East), api.eu.aws.sigmacomputing.com (AWS Europe), api.us.azure.sigmacomputing.com (Azure US), or api.sigmacomputing.com (GCP). Sigma displays the Client Secret a single time, at creation. If you lose it, you cannot view it again - you must regenerate the API client's credentials in Developer Access and update the Serval connection. There are no permission checkboxes anywhere in this process. The API client's access equals the account type of the Sigma user who owns it - many member, team, account type, and governance operations require an owner with the Admin account type. ## Connect in Serval Add a new Sigma Computing connection from your Serval integrations page. The **API Base URL** field is required and is described as "Your Sigma API base URL (without https\://). Find this in Administration > Developer Access > API base URL", with the placeholder aws-api.sigmacomputing.com. Enter the bare hostname only - a value with https\://, a path, or a trailing slash is rejected with "Must be a valid Sigma API base URL (e.g., aws-api.sigmacomputing.com, api.us-a.aws.sigmacomputing.com)". Leaving it empty shows "This field is required". The **Client ID** field is required and is described as "Client ID from your Sigma API credentials". Leaving it empty shows "This field is required". The **Client Secret** field is a required password field described as "Client Secret from your Sigma API credentials". Paste the complete secret you copied from Sigma. Save the connection. Serval stores the credentials and uses them to fetch Sigma access tokens automatically - workflows never handle tokens. When you later edit a saved connection, the Client Secret is displayed masked (bullet characters plus its last 4 characters). The stored secret is not carried over when you save changes, so always re-enter the complete Client Secret whenever you save - even if you are only updating the API Base URL or Client ID. If you no longer have the secret, regenerate the API client in Sigma's Developer Access first. The API Base URL and Client ID fields, by contrast, keep their saved values if you leave them blank on an update. ## Verifying the connection Saving the form stores the credentials without testing them against Sigma - this connection does not ship any built-in health checks, so there is no automatic healthy/unhealthy status to read. The credentials are first exercised when a workflow makes a call: Serval exchanges the Client ID and Client Secret for an access token at your API base URL and then runs the request. To confirm a new connection works, run a workflow that makes a simple read-only call - an identity lookup ("who am I") or listing workbooks both work well. An authentication failure on that first call means a wrong Client ID or Client Secret, a wrong regional API Base URL, or a revoked API client. A successful call proves the credentials authenticate - it does not prove they can do everything; admin operations still depend on the owning user's account type. ## Gotchas and troubleshooting On the edit form the Client Secret appears masked (bullets plus the last 4 characters). The stored secret is not carried over when you save changes, so re-enter the full, real Client Secret every time you save the connection - even when only the API Base URL or Client ID is changing. If the secret is lost, regenerate the API client in Sigma's Developer Access and paste the new secret. Blank API Base URL and Client ID values do keep their saved settings on update, but re-entering all three fields is the safest path. Enter the bare hostname only, for example aws-api.sigmacomputing.com. A value with https\://, a path, or a trailing slash fails with "Must be a valid Sigma API base URL (e.g., aws-api.sigmacomputing.com, api.us-a.aws.sigmacomputing.com)". The host must also be a known Sigma API domain - arbitrary domains are rejected by both the form and Serval's outbound allow-list. Sigma runs region-specific environments, each with its own API host, and both Serval's API requests and the token exchange use the domain you entered - so a wrong region means authentication fails even with a correct Client ID and Secret. Your exact base URL is shown in Sigma under Administration > Developer Access. Serval supports: aws-api.sigmacomputing.com (AWS US West), api.us-a.aws.sigmacomputing.com (AWS US East), api.ca.aws.sigmacomputing.com (AWS Canada), api.eu.aws.sigmacomputing.com (AWS Europe), api.uk.aws.sigmacomputing.com (AWS UK), api.au.aws.sigmacomputing.com (AWS Australia), api.us.azure.sigmacomputing.com (Azure US), api.eu.azure.sigmacomputing.com (Azure Europe), api.ca.azure.sigmacomputing.com (Azure Canada), api.uk.azure.sigmacomputing.com (Azure UK), and api.sigmacomputing.com (GCP). Sigma's OAuth does not use scopes and Serval requests none - API access equals the account type of the Sigma user who owns the API client. Many operations (members, teams, account types, connection grants) require an owner with the Admin account type. If those calls fail while others succeed, switch to an API client owned by an Admin. Sigma displays the Client Secret a single time when the API client is created. Copy it immediately and store it securely. If it is lost, regenerate the credentials in Developer Access and update the Serval connection with the new secret. Sigma access tokens are valid for one hour. Serval obtains and refreshes them automatically, so workflows never manage authentication and nothing needs to be rotated on a schedule - only if you regenerate the API client itself. Most list operations return a batch of entries plus a `nextPage` token. Pass that token back as the string `page` query parameter (optionally with `limit`) and repeat until `nextPage` is null - the `hasMore` field is deprecated in favor of `nextPage`. A small number of endpoints (account types, data model sources, and the v3 alpha endpoints) instead use `pageToken` and `pageSize` parameters with a `nextPageToken` response field. Paths in the "Sigma API request" action use curly-brace placeholders filled from the action's path parameters (for example a `{workbookId}` segment paired with a `workbookId` path parameter); colon-style segments such as `:workbookId` are not substituted. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Sigma Computing integration. # Slack Source: https://docs.serval.com/sections/integrations/slack Connect a Slack workspace to Serval to power your Slack help desk, deliver approval requests by DM, sync users and user groups, and run workflows against the Slack Web API. ## About Slack The Slack integration connects a single Slack workspace to your Serval team. It powers Serval's Slack help desk surfaces (tickets from channel messages and DMs, an @mention bot, an App Home tab, an AI assistant thread surface, a "Create a Ticket" message shortcut, and a slash command), delivers approval requests by direct message, and keeps your workspace's users and user groups synced into Serval. A separate [**Slack Admin**](/sections/integrations/slack-admin) integration (Enterprise Grid org-admin, user tokens) is documented on its own page and is not covered here. **Authentication:** Slack-app OAuth v2 install with bot scopes - either Serval's managed Slack app (one click, recommended) or your own white-label Slack app created from a Serval-generated manifest. **Data sync:** Scheduled background syncs ingest workspace users, and - once resource sync is on - user groups and their membership, on Serval's standard sync schedule; a manual sync from the UI forces a full re-sync. Workflow calls to Slack run on demand through Serval's proxy, and rate-limited responses are retried automatically with exponential backoff. ## What the Slack integration enables | Capability | Description | | - | - | | Help desk in Slack | Create tickets from channel messages and DMs, respond via an @mention bot, browse the App Home tab, use Slack's AI assistant thread surface, run the "Create a Ticket" message shortcut, or use a slash command named after your app. | | Approval requests via DM | Serval opens a direct message with each approver to deliver approval requests (requires the `im:write` bot scope). | | Channel management workflows | Create, rename, list, and search Slack channels - including public, private, private-plus-invite, and interest-group channel creation. | | User management workflows | Manage Slack user access and workspace membership: add or remove users from channels, invite, deactivate, or remove users (the invite, deactivate, and remove workflows run against the separate Slack Admin integration), and look up users and user groups. Workflows that change membership default to requiring the workflow installer's approval; read-only lookups run without approval. | | Enterprise Grid admin workflows | Manage Slack using the Admin API for Enterprise Grid organizations - these run against the separate Slack Admin integration, documented on its own page. | | User and user-group sync | Scheduled ingestion of workspace users, and of user groups with their membership. Turn on resource sync for the connection and Serval keeps each Slack user group current as a Serval group, so it can be selected in access policies and access-profile conditions; mentioning a synced group from Serval also renders as a proper group mention in Slack. Membership is managed in Slack - Serval reads it and never writes it back. | | Full Slack Web API in workflows | A typed API request action covers the Slack Web API. Slack is method-based rather than REST - you supply the method name (for example `chat.postMessage` or `users.lookupByEmail`) - with cursor-based pagination supported. Organization-admin methods are the one exception: they go through the separate Slack Admin integration. | | Incident broadcasts | During major incidents, a team member posts status updates from Serval. Requesters on linked tickets see them in Slack channels and threads. | Anything defined in the [Slack API](https://api.slack.com/methods) can be accessed through Serval, with one exception: organization-admin methods require the separate Slack Admin integration. A few of the catalog workflows above - name-based channel and user lookups, and inviting, deactivating, or removing workspace members - also connect through that companion Slack Admin integration rather than this one. ## Get your credentials There are two ways to connect, and only one of them needs any setup on Slack's side. No provider-side setup and no credentials are required. Choose **Use Serval's Slack App** - the option marked **Recommended** ("Connect instantly using Serval's managed Slack application.") - and Serval walks you through a standard Slack authorization screen. Skip ahead to **Connect in Serval**. Because the app requests the `incoming-webhook` scope, Slack will ask you to pick a channel during authorization. This is expected - the chosen channel is saved with the integration, and channel behavior is configured in Serval after connecting. On some self-hosted deployments this option is hidden (or returns the error "Slack OAuth is not configured in this environment"). In that case, use the **Your own Slack app** path instead. You'll create a Slack app from a manifest that Serval generates for you, then copy three values from the app's settings. See Slack's [app manifest reference](https://api.slack.com/reference/manifests) for background. Always use the manifest Serval generates in the connect dialog. Do not hand-write it or reuse one from docs or another environment - the webhook, interactivity, slash-command, and OAuth redirect URLs inside it are specific to your exact Serval deployment. In the Serval connect dialog, choose **Use Your Own Slack App**. Set your **App Name** (this appears in Slack when the bot sends messages), and adjust the **Bot Scopes** picker only if your Slack app will deliberately differ from the defaults. Click **Copy & Go to Slack** - this copies the generated manifest to your clipboard and opens [Slack's app creation page](https://api.slack.com/apps?new_app=1). In Slack, choose **From a manifest**, select the workspace to install into, paste the manifest, click **Next**, review the summary, and click **Create**. Upload a custom bot icon under **Basic Information > Display Information**. In [your app's settings](https://api.slack.com/apps), go to **Basic Information > App Credentials** and copy the **Client ID**, **Client Secret**, and **Signing Secret**. Plan to finish the Serval side within 10 minutes of submitting your credentials - the secure handoff token expires after that, and you would need to resubmit the form. ## Connect in Serval In the Slack connect dialog, select **Use Serval's Slack App** - the option marked **Recommended** ("Connect instantly using Serval's managed Slack application."). You're redirected to Slack's authorization screen. Make sure the correct workspace is selected (top-right), choose a channel when prompted, and click **Allow**. **App Name** - pre-filled with "Serval". Placeholder: "My Company IT". Helper text: "This appears in Slack when your app sends messages." If you clear the field, the connected integration is labeled "Custom App". The name is also slugified into your slash command (lowercase letters, numbers, underscores, and hyphens; up to 32 characters; falls back to "serval"). The **Bot Scopes** picker is pre-seeded with the 33 canonical defaults and has a **Reset to defaults** link. The field's own advice: "Deselect any scope your Slack app isn't configured with (e.g., Slack Connect scopes if your workspace restricts shared-channel invitations) to avoid being blocked during install." You can also add custom scopes that aren't in the suggestion list. An entry containing characters Slack scope names don't use is rejected with: Invalid Slack bot scope "\". Use Slack scope names like channels:read or files:write. Use **Copy & Go to Slack** and follow the provider-side steps above, then return and click **I have my credentials**. * **Client ID** (required) - placeholder "1234567890.1234567890". * **Client Secret** (required, masked) - placeholder "Enter your client secret". Used only during the OAuth exchange and never stored. * **Signing Secret** (required, masked) - placeholder "Enter your signing secret". Stored encrypted for webhook signature verification. The **Connect** button stays disabled until all three fields are filled in. Click **Connect**. You're redirected to Slack - make sure the correct workspace is selected (top-right), then click **Allow**. Complete this within 10 minutes of submitting the form. The connected integration is displayed as \ (\). When reconnecting later, any extra scopes you previously added are pre-merged back into the Bot Scopes picker - but scopes you previously deselected are not remembered, so deselect them again before reconnecting. Because the Client Secret is never stored, you'll enter your credentials again on reconnect. ## Configure Slack as your help desk After connecting, you land on the Slack app configuration page in Serval. To use Serval in a channel, first add it to the channel in Slack, then set that channel's mode in Serval. In the channel you want to use, type **@Serval** to mention the app and click **Add them** when prompted. The channel then appears on the Slack app configuration page in Serval. Go to **Integrations > Slack**, find the channel you just added Serval to, and choose how Serval should operate in it. See [Channel configuration modes](#channel-configuration-modes) for what each mode does. Repeat for any other channels: add Serval with **@Serval** then **Add them** in Slack, then set that channel's mode in Serval. You can also enable **Direct Messaging** from the Slack app's help desk settings for private support interactions. Channel-based support and DMs can run at the same time - channels give the team visibility, while DMs give users a private option for sensitive requests. On Slack **Enterprise Grid**, Serval supports org-wide (enterprise-level) channels shared across the workspaces in your Grid organization. Add Serval to an org-wide channel the same way (**@Serval**, then **Add them**), and it appears on the Slack app configuration page to set a mode. Messages posted from any workspace in the org, not only the one Serval was installed in, are handled. When first setting up, start a channel in **Silent** mode: Serval creates tickets without posting in the channel, so you can watch how tickets are created and routed before switching it to **Help Desk** mode to fully activate responses. ### Live agent chat in Portuguese For tickets with live agent chat enabled, the Portuguese button reads **🎧 Abrir um chat** when an agent is available and **🎧 Encerrar chat** while the chat is active. ### Control tickets in Slack Home Go to **Settings > Notifications > Slack** and use **Show tickets in Slack Home** to control whether the team’s open tickets appear in people’s **Assigned to you** and **Requests you filed** sections. Turning it off does not affect tickets owned by other teams, approvals, quick actions, or Slack notification delivery. The setting also applies when the Slack workspace connection is owned by another Serval team. If Slack Home is already open, revisit it to refresh the view. ## Channel configuration modes Each Slack channel connected to Serval operates in one of these modes: | Mode | Behavior | | - | - | | **Disabled** (default) | Serval does nothing in this channel - it neither creates tickets nor responds to messages. Use this to add Serval to a channel before turning any features on. | | **Help desk (Always respond)** | Full help desk: creates tickets from channel messages, posts ticket-detail cards in the channel, and the help desk agent attempts resolution using published skills and org-wide workflows. Escalates to a human when needed. | | **Help desk (When relevant)** | Same ticket creation and in-channel activity as **Help desk (Always respond)**, but the help desk agent replies only when it finds relevant context (knowledge, skills, matching workflows). If it cannot help, it stays silent in the channel and hands off to a human instead of posting a "no context" reply. | | **Silent** | Monitors the channel and creates tickets from messages, but does not post ticket-detail cards or agent replies in the channel. New tickets without an **@Serval** mention are routed to human triage without in-channel noise. Mentioning **@Serval** in a channel message or in an existing ticket's thread turns the agent on for that ticket. | | **On demand** | Ignores ambient channel messages. Creates a ticket and responds only when **@Serval** is mentioned in a top-level channel message. Once a ticket exists, replies in that ticket's thread reach the agent; mentions inside any other thread are ignored. | | **Team only** | For internal Serval-team channels. Full help-desk behavior plus access to team-only workflows. Use only in channels restricted to your Serval team members. | | **Redirect to DM** | New conversations are moved to a direct message with the requester before the help desk agent runs. A single notice is posted in the channel thread; ticket details and agent replies happen in the DM. | | **Team inbox** | A dedicated channel where support agents triage **all** tickets for the team (see [Configure Team Inbox channels](#configure-team-inbox-channels)). Egress-only: routes existing tickets into the channel for triage; does not create new tickets from messages posted directly in the inbox. | | **Team inbox on Escalation** | Same as **Team inbox**, but only **escalated** tickets are routed to the channel. Egress-only. | ## Configure Team Inbox channels A Team Inbox is a private channel where support agents triage every escalated ticket for your team within Slack. Tickets from DMs, help desk channels, and the web all appear as threads in one place, so agents can respond and collaborate without switching to the Serval web interface. Team Inbox is especially valuable when tickets come from DMs or other sources that individual support agents can't otherwise see. Create a private channel for the team's inbox (for example `it-inbox` or `finance-support-inbox`) and invite only the support agents and managers who will handle tickets - not end users. In the channel, type **@Serval** and click **Add them**, or connect the channel from the Slack app configuration page in Serval. In **Integrations > Slack**, find the channel and set its mode to **Team Inbox**. All escalated tickets for the team now sync into the channel automatically as threads. Once configured, each ticket appears as a thread with its details and history. Reply in a thread to send your message to the end user, and use commands like **@Serval assign to me** to triage. Team Inbox mode is egress-only. Messages posted directly to the channel (outside a ticket thread) do not create new tickets. ## Resource sync Serval supports resource sync for Slack **user groups** (Slack subteams - the `@`-mentionable groups in your workspace) and their membership. This is a separate capability from the help desk and from workflows: it does not sync channels or DMs, only user groups. In Serval, go to **Integrations > Slack** and open the app's settings page. Turn on **Resource sync**. Serval then ingests the workspace's active user groups and their members on its standard sync schedule; disabled groups are skipped. A manual sync from the UI forces a full re-sync. Each synced group becomes a Serval group whose members are the group's full workspace members (guests, bots, and accounts without an email are skipped), so you can pick it wherever Serval accepts a group - as approvers in an access policy, or in an access-profile condition. It is also cataloged with its name and `@handle` so the help desk agent and workflows can reference it - for example, when a reply needs to mention a Slack user group, Serval renders it as a proper group mention in Slack. This is a read-only sync: Serval mirrors which groups exist and who is in them, but it does **not** add or remove users from Slack groups through access requests (unlike Buildkite or OneLogin). Group membership stays managed in Slack. ## Verifying the connection After connecting, Serval runs five health checks: * **Test Slack Connection** - verifies the integration is connected and the OAuth token is valid. Success: "Successfully authenticated with Slack workspace \[workspace name]". Failure: "Unable to authenticate with Slack. Please verify the app is still installed and its OAuth token has not been revoked." * **List Slack Users** - checks Serval can read users from the workspace. Success: "Successfully listed Slack users (sample size: \[number])". Failure: "Unable to list Slack users. Please verify the app has the users:read scope and has not been removed from the workspace." * **List Slack Channels** - checks Serval can read public and private channels. Success: "Successfully listed Slack channels (sample size: \[number])". Failure: "Unable to list Slack channels. Please verify the app has the channels:read and groups:read scopes and has not been removed from the workspace." * **List Slack Scopes** - reports the OAuth scopes actually granted to the token. Success: "Successfully read Slack token scopes (\[number] granted)". Failure: "Unable to read Slack token scopes. Please verify the app is still installed and its OAuth token has not been revoked." * **Send Approval Requests via Slack** - checks the token has the `im:write` scope needed to open DMs for approval requests. Success: "Slack app has the im:write scope required to send approval requests." Failure: "Slack approval requests cannot be sent because the app is missing the im:write scope." If the check itself can't reach Slack, you'll instead see: "Unable to verify Slack approval request permissions. Please verify the app is still installed and its OAuth token has not been revoked." If the connection test is green but approval requests never arrive, run **List Slack Scopes** to see what the token was actually granted - the most common cause is a custom app installed without `im:write`. Fix the scopes in your Slack app and reconnect so a new token is issued. ## Gotchas and troubleshooting Slack blocks the install if Serval requests scopes your Slack app isn't actually configured with - the scopes requested at install time must all be present on your app. To change scopes on a custom app: adjust the **Bot Scopes** picker in Serval (which regenerates the manifest), update the app at api.slack.com with the new manifest (or matching scope edits), then reconnect so a token with the new grants is issued. Use the **List Slack Scopes** health check to see what the current token actually has. The default scope set includes the `conversations.connect` scopes for shared channels. If your workspace restricts shared-channel invitations, deselect those scopes in the **Bot Scopes** picker before installing. Note that a non-default selection replaces the canonical scope list wholesale (extra scopes you add are layered on top). Your Slack workspace has app approval turned on, so installing any new app - Serval's managed app or a custom app created from the manifest - requires a one-time approval by a Slack Workspace Owner, Workspace Admin, or App Manager. On Enterprise Grid, app management may instead be controlled at the organization level by org admins. This gate is entirely on Slack's side; your Serval permissions have no bearing on it. Approvals are also per-workspace: approval in a sandbox workspace does not carry over to production. To resolve it, submit the approval request on Slack's screen - the admin is notified via Slackbot and can approve under **Settings & administration > Manage apps > Requested apps** (Enterprise Grid: **admin.slack.com > Apps > Requests**) - or have the approving admin run the connect flow themselves. After approval, restart the connect flow from Serval; the earlier attempt does not resume. On the custom-app path that means re-entering your Client ID, Client Secret, and Signing Secret (the Client Secret is never stored) and completing the authorization within the 10-minute window, or the callback rejects with "Invalid state". Custom-app credentials travel in a signed token that expires 10 minutes after you submit the form. If you take longer than that to finish the Slack authorization, the callback rejects with "Invalid state". Re-open the connect dialog, resubmit your credentials, and complete the authorization promptly. For security, the Client Secret is used only during the exchange and is never stored; only the access token and Signing Secret are stored, encrypted. Expected. Because the app requests the `incoming-webhook` scope, Slack shows a channel selector on the authorization screen. The selected channel's id and name are saved with the integration, and channel behavior is configured in Serval after connecting. A Serval team can only have one Slack integration per workspace - either the managed app or a custom app, not both. To switch approaches, disconnect the existing integration first. Deployments without Serval-operated Slack credentials (for example, some self-hosted environments) can't use the managed one-click install - the connect dialog hides that option, or the attempt fails with "Slack OAuth is not configured in this environment". Use the **Use Your Own Slack App** flow instead. Even on Enterprise Grid, the integration connects a single workspace, not the whole organization - workspace-scoped actions like sending messages require a workspace connection, and the app is not org-deployed. Organization-level admin workflows require the separate **Slack Admin** integration, which uses different scopes and user tokens instead of bot tokens - see the [Slack Admin](/sections/integrations/slack-admin) docs page. The manifest is generated server-side so the webhook, interactivity, slash-command, and OAuth redirect URLs always match your exact Serval deployment. Copy it fresh from the connect dialog every time - never from documentation, a teammate, or another environment. Serval refuses to generate a manifest with an unreachable webhook address rather than emit a broken one. The default set is exactly 33 bot scopes: app\_mentions:read, channels:history, channels:join, channels:manage, channels:read, channels:write.invites, chat:write, chat:write.customize, commands, conversations.connect:manage, conversations.connect:read, conversations.connect:write, files:read, files:write, groups:history, groups:read, groups:write, im:history, im:read, im:write, incoming-webhook, metadata.message:read, mpim:history, mpim:read, reactions:read, reactions:write, team:read, usergroups:read, usergroups:write, users:read, users:read.email, users.profile:read, and assistant:write. No user-level scopes are requested for regular Slack installs. See Slack's [permission scopes reference](https://api.slack.com/scopes) for what each scope grants. *** Need help? Contact [**support@serval.com**](mailto:support@serval.com) for assistance with your Slack integration. ## Configure existing helpdesk channels through the API You can activate an existing Slack channel or change its helpdesk mode from an external API client or a Serval workflow. The channel must already appear in **Add another channel** in your Slack integration. Inviting the bot alone does not guarantee that Serval has discovered the channel. 1. Call `GET /v2/teams/{team_id}/connected-channels`. You can filter by `serviceInstanceId` to select the Slack integration instance. Disabled channels are included; direct messages and deleted connections are excluded. 2. Find the entry whose `serviceChannelId` matches your Slack channel ID. 3. Call `PUT /v2/teams/{team_id}/connected-channels/{id}/mode`, using the entry's Serval `id`, with this body: ```json theme={null} { "mode": "CONNECTED_SERVICE_MODE_FULL_ASSIST" } ``` This enables **Help desk (Always respond)**, matching the channel picker. The response contains the resulting channel in `data`. Repeating the same mode succeeds without another change. Use `CONNECTED_SERVICE_MODE_DISABLED` to disable the channel. External clients use Serval API authentication. Scoped Serval API keys need `channels:read` for listing and `channels:write` for updates, plus access to the requested team. These are Serval scopes, not Slack OAuth scopes. A write-only key can update a connection whose ID you already know. Serval workflows use their existing team-bound credentials. With `serval` imported from the Serval SDK, the API calls look like this: ```typescript theme={null} const channels = await serval.apiRequest({ method: "GET", path: "/v2/teams/{team_id}/connected-channels", pathParams: { team_id: teamId }, query: { serviceInstanceId }, }, undefined); const channel = (channels.data ?? []).find( (entry) => entry.serviceChannelId === slackChannelId, ); if (!channel?.id) { throw new Error("Channel is not available in this team's connected channels."); } await serval.apiRequest({ method: "PUT", path: "/v2/teams/{team_id}/connected-channels/{id}/mode", pathParams: { team_id: teamId, id: channel.id }, body: { mode: "CONNECTED_SERVICE_MODE_FULL_ASSIST" }, }, undefined); ``` The API supports these existing Slack modes: | Mode value suffix | Integration setting | | - | - | | `DISABLED` | Disabled | | `FULL_ASSIST` | Help desk (Always respond) | | `ASSISTANT` | Help desk (When relevant) | | `TICKET_ONLY` | Silent | | `ON_DEMAND` | On demand | | `TEAM_ONLY` | Team only | | `TEAM_INBOX_ALL` | Team inbox | | `TEAM_INBOX` | Team inbox on Escalation | | `REDIRECT_TO_DM` | Redirect to DM; requires direct messages enabled for the team | Prefix each value with `CONNECTED_SERVICE_MODE_`. The mode must be explicit. `DM`, `SILENT_ASSIST`, `UNSPECIFIED`, and unknown values cannot be set. Existing redirect messages are preserved. The API does not create connections, invite the bot, or configure direct messages, phone/WhatsApp senders, or email intake. # Slack Admin Source: https://docs.serval.com/sections/integrations/slack-admin Connect Slack's Enterprise Grid admin tools to Serval so workflows can invite, deactivate, and remove users and manage channel membership across your entire Slack organization. ## About Slack Admin Slack Admin (shown in Serval as **Slack Enterprise Admin**) is the org-administration companion to the regular [Slack integration](/sections/integrations/slack). It connects to your Slack Enterprise Grid organization as one of your org admins and runs every action with that person's own permissions, so workflows can invite, deactivate, and remove users, manage channel membership, and look up people and channels across the whole org. The regular Slack integration still handles messaging, channel creation, user and group sync, and ticket sync - flows that both message people and manage the org need both connections. **Authentication:** OAuth, authorized by an Enterprise Grid org admin or org owner. Either one click via Serval's managed Slack Admin app, or bring your own Slack app (created from a manifest Serval provides) using its Client ID and Client Secret. **Data sync:** None. Slack Admin runs no scheduled syncs or background ingestion - everything executes on demand inside workflow runs using the stored admin token. User and group sync run through the regular Slack integration. ## What the Slack Admin integration enables | Capability | Description | | - | - | | Admin API requests | Call any method in Slack's Enterprise Grid admin family as the connected admin - list, invite, and remove users, search channels, list workspaces, and more. Failed calls surface Slack's full error response so workflows fail loudly. | | SCIM API requests | Call Slack's SCIM provisioning API, which powers full account deactivation. | | Name and email lookups | Find a channel by name (archived channels excluded) or a user by email address, so workflows can use human-friendly names instead of Slack IDs. No match raises an error, and an ambiguous channel-name match is rejected rather than guessed. | | User lifecycle helpers | Invite a user to a workspace (with a starter channel), remove a user from a workspace, or deactivate their account entirely. | | Channel membership helpers | Add a user to a channel (channel by name or ID, user by email) or remove them - including private channels. | | Installable "Admin API" workflows | A ready-made bundle in the Slack workflow catalog ("Manage Slack using the Admin API for Enterprise Grid organizations"): "Get Channel (Admin API)", "Get User (Admin API)", "Deactivate User (Admin API)", "Invite User (Admin API)", "List Teams (Admin API)", "Remove User from Slack Channel (Admin API)", and "Remove User from Workspace (Admin API)". Read-only workflows install without an approval step; workflows that change things default to requiring installer approval. | Anything defined in the [Slack Admin API](https://api.slack.com/methods) can be accessed through Serval. ## Get your credentials There are two ways to connect. The managed app is the fastest; bring your own app when your organization requires apps it controls or wants to trim the requested scopes. There is nothing to create. You just need the right person to click the button: an Enterprise Grid org admin or org owner - ideally the **primary org owner**, who has the most permissions. The admin permissions are granted to the person who authorizes, and Serval stores that person's token. Slack only grants these admin permissions on Enterprise plans, to org admins and owners. The connection is keyed to your Slack Enterprise organization (with a fallback for older "Enterprise Select" orgs). In some environments (mostly self-hosted deployments) Serval's managed credentials are not configured. The "Use Serval's Slack App" option is hidden and connection attempts show "Slack Admin OAuth is not configured in this environment". Use the bring-your-own-app path instead - it works with your own credentials. You create a Slack app inside your own Enterprise Grid org from a manifest Serval renders for you, then hand Serval that app's Client ID and Client Secret. The manifest already contains the correct redirect URL and scope lists, and is set up for organization-level installs. Manage your apps at [api.slack.com/apps](https://api.slack.com/apps). In the Serval connect modal, optionally adjust **App Name** and the **Bot Scopes** / **User Scopes** pickers, then click "Copy & Go to Slack". This copies the rendered manifest and opens [Slack's app creation page](https://api.slack.com/apps?new_app=1). At Slack, create the app "From a manifest" and paste the copied JSON. Do not edit the redirect URL or scopes by hand - the manifest is generated to match exactly what Serval's connection flow expects. Open your new app at [api.slack.com/apps](https://api.slack.com/apps), go to **Basic Information > App Credentials**, and copy the **Client ID** and **Client Secret**. Back in Serval, click "I have my credentials", paste the Client ID and Client Secret, and click Connect. Complete the Slack authorization as an org admin or owner - the admin permissions are granted to **you**, and Serval stores your user token. No signing secret is needed. The admin app receives no webhooks - it has no event subscriptions, interactivity, or slash commands. The scopes Serval requests must exactly match what your Slack app is configured with, or Slack blocks the install. If you trimmed scopes on the app (commonly the Slack Connect scopes under `conversations.connect`), mirror that change in the Bot Scopes / User Scopes pickers before connecting. ## Connect in Serval Find **Slack Enterprise Admin** in Serval's available integrations and open the connect flow. When Serval's managed app is available you can simply choose "Use Serval's Slack App" and authorize in Slack as an org admin or owner - you are done. Otherwise choose "Use Your Own Slack App" and continue with the custom app form below. * **App Name** (optional). Pre-filled with "Serval Admin"; placeholder "My Company IT", helper text "This appears in Slack when your app sends messages." Cleared and left blank, the manifest falls back to "Serval Admin" and your connection is named "\[Enterprise name] (Custom App)". * **Bot Scopes** (optional). Pre-filled with the 31 default bot scopes; placeholder "Search or add a Slack bot scope...". Changing the selection **replaces** the default set wholesale; use the "Reset to defaults" link to restore it. Invalid entries are rejected with: Invalid Slack bot scope "\[scope]". Use Slack scope names like channels:read or files:write. * **User Scopes** (optional). Pre-filled with the 19 default user scopes; placeholder "Search or add a Slack user scope...". An invalid entry shows the bot-flavored message on screen; the server reports: invalid Slack user scope "\[scope]"; use scope names like admin.users:read or mpim:write. * **Client ID** (required). Placeholder "1234567890.1234567890". The backend rejects a blank value with "slackClientId is required". * **Client Secret** (required). Password field, placeholder "Enter your client secret". The backend rejects a blank value with "clientSecret is required". The Connect button stays disabled until both Client ID and Client Secret are filled in. Click Connect and complete the Slack authorization as an org admin or owner. Finish within 10 minutes - your credentials travel in a signed, time-limited handoff that expires after that. Serval then discards your Client Secret and stores your encrypted admin user token, along with the app's bot token for the Slack Connect invite endpoints. The connection appears as "\[Enterprise name] (\[App name])". There is no separate edit-credentials form for this integration. To update credentials later, run the connect flow again with both Client ID and Client Secret. Serval never stores the Client Secret, so there is no stored value to leave in place. ## Verifying the connection Slack Admin ships **no health checks**. The health checks you may see under Slack belong to the regular Slack connection, not this one. To confirm the connection works, install a read-only workflow from the "Admin API" bundle in the Slack workflow catalog and run it - "List Teams (Admin API)" is the simplest: it lists the workspaces in your org without changing anything. "Get Channel (Admin API)" and "Get User (Admin API)" are also safe, read-only checks. If the connection authorizes fine but admin workflows fail with Slack permission errors, the authorizing admin is usually missing org-level permissions such as "Manage public channels for a team" or "Manage private channels at the org level" (in Slack org settings under **People > Manage permissions**). Grant the missing permissions, or reconnect as the primary org owner. ## Gotchas and troubleshooting The connection's primary credential is the authorizing admin's own user token - the bot token from the install is stored too, but used only for the Slack Connect invite endpoints (`conversations.requestSharedInvite.*`), which require a bot-only scope. Every other workflow call assumes that person's permissions, so anything their Slack role cannot do surfaces as a permission error at runtime. If that admin changes roles or is deactivated, the connection breaks until someone reconnects. The token is long-lived with no refresh flow (token rotation is deliberately disabled in the app manifest). Slack only grants the admin permissions to Enterprise org admins and owners, and the connection is keyed to your Enterprise Grid organization (older "Enterprise Select" orgs fall back to the workspace). Connect as the primary org owner where possible - other org owners and admins may lack default permissions like "Manage public channels for a team" or "Manage private channels at the org level", which causes runtime permission errors. This connection only covers Slack's admin methods, user methods, oversight methods, the SCIM API, the Slack Connect invite methods, and one channel-removal method. Messaging, channel creation, user and group sync, and ticket sync all live on the regular [Slack integration](/sections/integrations/slack) - flows that both message people and manage the org need both connections. The Admin API catalog workflows even ship inside the Slack integration's workflow catalog. For bring-your-own apps, the authorization request must only ask for scopes your Slack app is actually configured with. The Bot Scopes / User Scopes pickers replace the default sets when changed, precisely so teams that trimmed scopes (commonly the Slack Connect scopes under `conversations.connect`) are not blocked at install. After editing scopes on the Slack app itself, mirror the change in the pickers before reconnecting. The org-level install goes through Slack's app-approval gate like any other app: if your organization requires admin approval for new apps, the authorization screen asks you to request approval instead of offering **Allow** - for the managed app and bring-your-own apps alike. On Enterprise Grid, approvals are handled at **admin.slack.com > Apps > Requests**. The org admin or owner authorizing this integration often holds app-management rights and can approve the app themselves; otherwise submit the request or have an app manager approve it. After approval, rerun the connect flow from Serval - the earlier attempt does not resume, and on the bring-your-own path you enter the Client ID and Client Secret again (the Client Secret is never stored) and finish within the 10-minute handoff window. "Remove User from Workspace (Admin API)" uses Slack's `admin.users.remove` method and explicitly does **not** deactivate the account. "Deactivate User (Admin API)" goes through Slack's SCIM API and disables the account itself. Pick the right one for offboarding. Slack exposes no admin-family method for kicking a user from a channel, so channel removal deliberately uses the standard `conversations.kick` method with the admin's user token. The default user scopes include the non-admin `channels:write` and `groups:write` scopes specifically so removal works in both public and private channels - keep them if you customize scopes. Health checks are matched by integration, and none exist for Slack Admin - the Slack health checks belong to the regular Slack connection. Verify with a read-only catalog workflow such as "List Teams (Admin API)" instead. If Serval's Slack Admin credentials are not configured in your environment (relevant mostly to self-hosted deployments), the managed connect path is unavailable and shows "Slack Admin OAuth is not configured in this environment". The bring-your-own-app path still works since it uses your credentials. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Slack Admin integration. # Smartsheet Source: https://docs.serval.com/sections/integrations/smartsheet Connect Serval to the Smartsheet API to read and update the tasks in your project sheets. ## About Smartsheet The Smartsheet integration lets Serval workflows read the tasks in a project sheet and update them. In Smartsheet a task is a row, and each task field is a cell in a column the sheet owner named, so the included workflows address columns by title (for example, Status or Assigned To). Workflows can read any sheet, report, workspace, or other object the connected user can open, and can add, update, and delete rows and comment on rows. Attachments, sharing, and user administration are not available through this integration. **Authentication:** A Smartsheet API access token. Serval stores the token securely and sends it as a bearer token only to the Smartsheet API host for the region you select (United States, European Union, or Australia). Smartsheet Gov is not supported. **Data sync:** On demand. Serval reads from Smartsheet when a workflow runs and does not perform a background sync. API access requires a Smartsheet Business, Enterprise, or Advanced Work Management plan. ## Create an API access token Workflows act as the Smartsheet user who owns the token. We recommend a dedicated service-account user, shared into every sheet your workflows use, with **Editor** access or higher on sheets where workflows make changes. Sign in to Smartsheet as the user Serval will act as. Select your profile image at the bottom of the left navigation, choose **Personal Settings**, and open the **API Access** tab. Select **Generate new access token**, name it Serval, and copy the token. Smartsheet shows it only once. See [Smartsheet's guide to generating an API access token](https://help.smartsheet.com/articles/2482389-generate-API-key) for the current steps. ## Connect in Serval Enter a recognizable instance name, such as Production. Choose United States, European Union, or Australia. Accounts that sign in at app.smartsheet.eu are in the EU region, and accounts that sign in at app.smartsheet.au are in the Australia region. Paste the API access token and submit the form. ## Verify the connection Serval checks that it can read the token's own user and list the sheets shared with it. A failed check usually means the token is invalid or revoked, the wrong region was selected, or the account's plan does not include API access. ## Included workflows | Workflow | What it does | Default approval | | - | - | - | | List Smartsheet Tasks | Returns each task's row ID and cell values keyed by column title, optionally only tasks changed since a given time | None | | Update Smartsheet Task | Sets cell values on one task by column title | Installer | | Add Smartsheet Task | Adds a task at the bottom of the sheet or as a subtask under another task | Installer | The update and add workflows refuse, without changing anything, when a column does not exist, is calculated by Smartsheet (such as Created By or an auto-number column), is locked and the token's user is not the sheet owner or an admin, holds a formula, or is linked from another sheet. Multi-select dropdown and multi-contact columns can be written only through a custom workflow. Smartsheet allows 300 API requests per minute per token and rejects concurrent writes to the same sheet. Serval waits and retries when either limit is hit. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Smartsheet integration. # Snipe-IT Source: https://docs.serval.com/sections/integrations/snipeit Connect your Snipe-IT asset management instance so Serval workflows and Catalyst can look up, check out, and manage your hardware, licenses, and users. ## About Snipe-IT [Snipe-IT](https://snipeitapp.com) is an open-source IT asset management (ITAM) platform for tracking hardware, licenses, accessories, consumables, and components. The Serval integration connects to your own Snipe-IT instance - cloud-hosted (such as your-company.snipe-it.io) or fully self-hosted on any domain - using a personal API key generated inside Snipe-IT. Once connected, Serval workflows and Catalyst can work with your full Snipe-IT inventory: asset checkout and checkin, user lookups, license seat management, audits, and more. See the [Snipe-IT documentation](https://snipe-it.readme.io/docs) for product details. **Authentication:** API key (Bearer token) - your instance domain plus a personal API key created in Snipe-IT. **Data sync:** On-demand only. Serval contacts your Snipe-IT instance when a workflow or Catalyst runs an action - there is no background sync or scheduled import. Health checks confirm the connection stays healthy. ## What the Snipe-IT integration enables | Capability | Description | | - | - | | Hardware assets | List, create, update, and delete assets; look up by asset tag or serial number; check assets out and in; restore deleted assets; manage asset files; see licenses linked to an asset. | | Asset audits | Record asset audits and list assets with audits due or overdue. | | Users | Manage users, restore deleted users, and view a user's assigned assets, accessories, licenses, and accepted EULAs. | | Licenses and seats | Full license management, plus listing license seats and updating individual seat assignments. | | Accessories, consumables, and components | Create, update, and delete all three; check accessories and components out and in; check out consumables; and see who or what each item is checked out to. | | Models, categories, manufacturers, and suppliers | Manage the asset catalog, including model files. | | Status labels | Manage status labels and list the assets carrying each label. | | Companies, locations, departments, and groups | Manage the organizational structure records used for asset assignment and multi-company setups. | | Custom fields and fieldsets | Manage custom fields and fieldsets, including associating and disassociating fields with fieldsets. | | Maintenance, reports, and backups | Manage asset maintenance records, pull the activity report, and list or download settings backups. | Anything defined in the [Snipe-IT API](https://snipe-it.readme.io/reference/api-overview) can be accessed through Serval. ## Get your credentials Serval connects with a personal API key created inside your Snipe-IT instance. The key acts with the permissions of the user who creates it, so use an account that can view (and, if your workflows write data, manage) everything your workflows will touch. Snipe-IT's own guide is at [Authenticating with the Snipe-IT API](https://snipe-it.readme.io/reference/authenticating-with-the-api). For example, [https://your-company.snipe-it.io](https://your-company.snipe-it.io), or your self-hosted domain. Click your account dropdown in the top-right corner and select **Manage API Keys**. Click **Create New Token** and give it a descriptive name (for example, "Serval Integration"). Keep it somewhere safe until you have pasted it into Serval. Snipe-IT shows the API key only once. If you lose it, you must generate a new one. The key inherits the permissions of the user who created it. A key from an under-permissioned account will connect but fail the permission health checks below. ## Connect in Serval In Serval, open the Snipe-IT integration and start a new connection. Enter your instance base domain, for example your-company.snipe-it.io. As the helper text says, do not include /api/ or /v1/ paths. Leaving it empty shows "This field is required". You can paste a full URL - Serval automatically strips https\:// or http\:// prefixes, trailing slashes, and trailing /api, /api/v1, or /v1 segments when saving. Paste the key you copied from Snipe-IT. The field hides the value as you type. Saving the form does not test the key against Snipe-IT. Verification happens right afterward via the health checks below. When editing an existing connection, the form pre-fills your saved Snipe-IT URL, and the API Key appears as a masked value (bullets plus the last 4 characters of the saved key) with a control to replace it. Leave the key untouched and the stored key is kept. Any field that reaches Serval blank also keeps its stored value - so you can rotate the key without re-typing the domain, or fix the domain without re-pasting the key. ## Verifying the connection After you connect, Serval runs three health checks against your instance: * **Validate Snipe-IT API Connection** - confirms your instance is reachable and the API key authenticates. * Success: "Successfully connected to Snipe-IT API." * Failure: "Unable to connect to Snipe-IT API. Please verify your API key is valid and has the necessary permissions." * **List Users** - confirms the key can read users and reports your user count. * Success: "Successfully listed users. Found \[number] users in Snipe-IT." * Failure: "Unable to list users. Please verify your API key has user read permissions." * **List Hardware Assets** - confirms the key can read hardware assets and reports your asset count. * Success: "Successfully listed hardware assets. Found \[number] total assets in Snipe-IT." * Failure: "Unable to list hardware assets. Please verify your API key has hardware read permissions." Counts are filled in at runtime; when the total is 1, the message uses the singular "user" or "asset". If "Validate Snipe-IT API Connection" passes but "List Users" or "List Hardware Assets" fails, your key is valid but the Snipe-IT user who created it lacks read access to that resource. Grant that user the missing permission in Snipe-IT - permissions are evaluated live, so the check passes on the next run without re-entering the key. ## Gotchas and troubleshooting Submitting the form saves the connection without making a live call to Snipe-IT. A wrong or under-permissioned key only shows up afterward, when the health checks run. If a health check fails right after connecting, re-check the key rather than the form. Enter just the base domain (for example, your-company.snipe-it.io). Serval auto-cleans common extras - https\:// or http\:// prefixes, trailing slashes, and trailing /api, /api/v1, or /v1 segments - but a URL that still contains /api/ or /v1/ in the middle of the path is rejected. The rejection surfaces only as a generic failure (such as "Failed to connect service" or "Failed to install integration") without a specific explanation, so if connecting keeps failing, the URL is the first thing to fix. Snipe-IT API keys act with the permissions of the user who created them. The "List Users" and "List Hardware Assets" health checks fail independently if that user lacks read access to those resources - create the key from an account whose permissions cover everything your workflows touch. When editing the connection, the saved Snipe-IT URL is pre-filled and the API Key shows as a masked value (bullets plus the last 4 characters). An untouched key is never overwritten, and a field that reaches Serval blank - an emptied URL, or a key you started replacing but left empty - keeps its stored value. Serval re-runs the health checks automatically after you save an update. Snipe-IT returns list results in pages: a total count plus one batch of rows per request, advanced with an offset rather than a cursor. Workflows that walk a large inventory must request successive pages, increasing the offset until the whole total has been covered - a single request will not return everything. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Snipe-IT integration. # Snowflake Source: https://docs.serval.com/sections/integrations/snowflake Connect Serval to your Snowflake account with a Programmatic Access Token so workflows can run SQL and manage Snowflake objects on demand. ## About Snowflake Snowflake is a cloud data platform for storing and querying data. Serval connects to a single Snowflake account using a Programmatic Access Token (PAT) and calls Snowflake's REST APIs - including the SQL Statement API and the object-management APIs - on demand from your workflows. There are no prebuilt helper functions: every workflow request goes through one generic "Snowflake API request" action, which Serval forwards to your connected account's domain with your token attached. **Authentication:** Programmatic Access Token (PAT) **Data sync:** On-demand only. Serval never syncs or ingests Snowflake data in the background - Snowflake is queried or modified only when a workflow step runs. ## What the Snowflake integration enables | Capability | Description | | - | - | | Execute SQL statements | Run query, DML, and DDL statements through Snowflake's SQL Statement API, optionally specifying the database, schema, warehouse, role, bindings, and timeout for each statement. | | Poll and fetch large result sets | Check the status of asynchronous or long-running statements and retrieve results partition by partition once they complete. | | Cancel running statements | Stop a previously submitted statement that is still executing. | | Manage Snowflake objects | Work with Snowflake's object-management APIs - databases, schemas, tables, views, warehouses, users, roles, grants, tasks, streams, pipes, stages, network policies and rules, and more - subject to the privileges of the PAT's role. | | Use Cortex AI | Call Snowflake Cortex APIs, including Cortex Analyst, Cortex Inference, Cortex Search, and the OpenAI- and Anthropic-compatible Cortex endpoints. | In total, the integration covers 46 Snowflake REST API surfaces. Anything defined in the [Snowflake API](https://docs.snowflake.com/en/developer-guide/snowflake-rest-api/snowflake-rest-api) can be accessed through Serval. ## Get your credentials You'll create a Programmatic Access Token (PAT) for the Snowflake user Serval should act as - ideally a dedicated service user with a narrowly scoped role. See Snowflake's [Programmatic Access Tokens documentation](https://docs.snowflake.com/en/user-guide/programmatic-access-tokens) for full details. Using the `ACCOUNTADMIN` role, create a user just for Serval, e.g. `CREATE USER SERVAL_USER COMMENT = 'Service account for Serval integration';` Create a role with only the privileges Serval needs (warehouse and database usage, access to the relevant schemas and tables), then assign it: `GRANT ROLE SERVAL_ROLE TO USER SERVAL_USER;` Snowflake requires service users to be covered by a network policy before a PAT can be generated or used for them (by default this applies to human users authenticating with a PAT too). Create a network rule that allow-lists Serval's egress IP addresses, wrap it in a network policy, and assign it: `ALTER USER SERVAL_USER SET NETWORK_POLICY = SERVAL_NETWORK_POLICY;` Contact **[support@serval.com](mailto:support@serval.com)** to get the current list of Serval egress IPs for your network rule. Without a network policy assigned to the user, Snowflake refuses PAT authentication for service users. In Snowsight, go to **Profile → Programmatic access tokens**, or use SQL: `ALTER USER SERVAL_USER ADD PROGRAMMATIC ACCESS TOKEN serval_pat ROLE_RESTRICTION = 'SERVAL_ROLE' DAYS_TO_EXPIRY = 90;` By default a PAT expires after just 15 days, so set an explicit expiry that matches your rotation schedule. Copy the token immediately - Snowflake shows it only once. If your browser URL is `https://app.snowflake.com///...`, your account URL is `-.snowflakecomputing.com` - this form works regardless of which cloud your account runs on. Older locator-style addresses with extra labels (for example `xy12345.us-east-1.snowflakecomputing.com`) are also accepted. Or run: `SELECT CURRENT_ORGANIZATION_NAME() || '-' || CURRENT_ACCOUNT_NAME() || '.snowflakecomputing.com';` ## Connect in Serval In Serval, go to **Integrations**, open the **All integrations** tab, find **Snowflake**, and click **Connect**. The "Configure Snowflake" form appears. Enter the bare account domain, e.g. `myorg-account123.snowflakecomputing.com` - no `https://` prefix, no path, and no stray spaces. The field's helper text reads "Your Snowflake account identifier (without https\://)". Multi-part domains like `account.region.cloud.snowflakecomputing.com` are accepted, and uppercase input is automatically lowercased when saving. If the value doesn't match the expected format, the form shows: `Invalid account URL. Expected format: [.].snowflakecomputing.com`. Serval's server applies the same checks when saving and responds with "accountUrl is required" or "invalid accountUrl format: must be a valid Snowflake account domain (e.g. account.region.snowflakecomputing.com)" if something slips through. Paste the PAT into the **Access Token** password field (placeholder: "Programmatic Access Token"). The helper text reminds you where to create one: "Generate a PAT in Snowflake: Profile → Programmatic access tokens". Leaving it empty is rejected with "accessToken is required". Serval checks the Account URL format and that a token was entered, then saves the connection. The token is stored encrypted. Serval does **not** make a live test call to Snowflake when you connect - a mistyped, expired, or under-privileged token is accepted here and only fails on first use. Serval only ever sends your token to your own Snowflake address - hosts ending in .snowflakecomputing.com. Any other destination receives no credentials. When editing the connection later (for example, to rotate a token), the saved Account URL appears pre-filled, but the Access Token field is always empty - Serval never displays the stored token, even in masked form. Every update must include a token: saving with the token field blank is rejected with "accessToken is required". Have the new PAT ready before you start. ## Verifying the connection This integration has no automated health checks, so a saved connection shows no pass/fail status on its own. To confirm your credentials work, run a trivial statement - such as `SELECT CURRENT_USER()` - through the "Snowflake API request" action in a test workflow. A successful response confirms the account URL, token, and network policy are all set up correctly. Because connect-time validation is format-only, a connection can save without errors and still fail on its first workflow request. If the very first call returns an authentication error, check the token value, its expiry, and the user's network policy - in that order. ## Gotchas and troubleshooting Serval validates only the format of the account URL and the presence of the token at connect time - it never makes a live call to Snowflake. A typo'd, expired, or under-privileged PAT is accepted by the connect form and only fails later, typically as an authentication (401) error on the first workflow request. Re-check the token in Snowflake and re-enter it in the connection settings. Snowflake requires service users to be covered by a network policy before their PATs can be used, and by default human users need one to authenticate with a PAT as well. Create a network rule allow-listing Serval's egress IPs (contact **[support@serval.com](mailto:support@serval.com)** for the list), wrap it in a network policy, and assign it to the user. PATs expire - by default after just 15 days unless you set a longer expiry when creating the token. When the token expires, every request returns an authentication error. Generate a new PAT in Snowflake and update the connection's Access Token in Serval - ideally before the old one expires. The Account URL must be a bare `*.snowflakecomputing.com` domain. Values containing `https://`, a trailing path, stray spaces, or any other host are rejected with `Invalid account URL. Expected format: [.].snowflakecomputing.com`. Capitalization is never the problem - uppercase letters are lowercased automatically when the connection is saved. This is expected. The Access Token is write-only - Serval never displays the stored value - so the field is empty whenever you edit the connection, and saving with it blank is rejected. Keep the PAT value somewhere safe (or generate a fresh one) before re-saving the connection. Snowflake's SQL Statement API does not support PUT, GET, USE, ALTER SESSION, BEGIN, COMMIT, ROLLBACK, statements that set session variables, or statements that create temporary tables and stages. Instead of issuing USE statements, specify the database, schema, warehouse, and role in the statement request itself. If a statement doesn't finish within 45 seconds, Snowflake returns a statement handle instead of results, and the caller must poll the statement's status for completion (large results are returned in partitions). You can also set the async option to true to get the handle-based flow up front for known long-running statements. There are none - the integration exposes a single generic action, "Snowflake API request", and no helper functions. All workflow interaction with Snowflake goes through that one action, which proxies an authenticated request to your account's domain. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Snowflake integration. # Socket Source: https://docs.serval.com/sections/integrations/socket Serval's Socket integration lets you automate **software supply-chain security**: vet open-source dependencies, monitor supply-chain alerts, run and gate on dependency scans, triage findings, and export SBOMs. The integration connects via a Socket organization API token. *** ## What is Socket? [Socket](https://socket.dev) analyzes open-source packages (npm, PyPI, Maven, Go, and more) for supply-chain risk — malware, typosquats, risky install scripts, hijacked maintainers, known CVEs, and license issues — and scores every package's health. Organizations connect Socket to their repositories and enforce security policies on the dependencies entering their code. *** ## What Serval can do once connected | Capability | Description | | - | - | | Vet packages | Look up Socket health scores, alerts, and license data for any package before adopting it | | Monitor alerts | List and filter the organization's supply-chain alerts (severity, category, repository, known-exploited CVEs) | | Scans | Create full scans from manifest files, check scan state and results, create diff scans for change gating | | Triage | Create triage rules and resolutions that ignore, monitor, warn on, or block matching alerts | | SBOM export | Export scans as CycloneDX, SPDX, or OpenVEX documents (Socket Business plan and above) | | Automation workflows | Call any endpoint in the curated [Socket REST API](https://docs.socket.dev/reference) subset exposed by the integration | Socket meters API usage in hourly **quota units** that vary by plan (Free 500/hr, Team 2,500/hr, Business 10,000/hr). Alert listing costs 10 units per request and batch package lookups cost 100, so schedule polling workflows accordingly. *** ## Configure Socket ### Prerequisites * A Socket organization you can administer * Permission to create an organization API token ### Create an API token 1. In Socket, open **Settings → API Tokens** 2. Click **Create API Token** 3. Configure the token: * **Name**: e.g. `Serval Integration` * **Scopes**: enable the scopes below 4. Create the token and copy the value — it is only shown once ### Suggested scopes | Scope | Used for | | - | - | | `packages:list` (+ `pkg:npm`, `pkg:pypi`, ... per ecosystem) | Package vetting lookups | | `full-scans:list`, `full-scans:create` | Listing, creating, and checking scans | | `diff-scans:list`, `diff-scans:create` | Diff scans for change gating | | `alerts:list` | Listing supply-chain alerts, healthchecks | | `triage:alerts-list`, `triage:alerts-update` | Reading and creating triage rules | | `alert-resolution:list`, `alert-resolution:create` | Resolving alerts with a recorded reason | | `repo:list` | Listing repositories, healthchecks | | `report:read` | SBOM export (Business plan and above) | | `fixes:list` | Vulnerability fix lookups | *** ## Serval Configuration 1. In Serval, go to **Integrations → All integrations → Socket → Connect** 2. Enter: | Field | Description | | - | - | | Organization Slug | Your Socket org slug (from the dashboard URL, e.g. `my-company` in `socket.dev/dashboard/org/my-company`) | | API Token | The token you created above | 3. Click **Save** Serval validates the connection and runs healthchecks for authentication, organization access, repository listing, and alert listing. Once verified, the integration shows **Healthy** on the Integrations page. ### Managing access later * **Rotate token** — Rotate the token in Socket (Settings → API Tokens), then update the token in Serval's integration settings * **Disconnect** — Remove the integration from Serval; revoke the token in Socket *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Socket integration. # Sonos Source: https://docs.serval.com/sections/integrations/sonos Connect your Sonos account so Serval workflows can discover speakers, play saved favorites, and control grouping, playback, and volume through the cloud. ## What you can automate The Sonos integration controls speakers through the [Sonos cloud Control API](https://docs.sonos.com/docs/control). It includes typed API requests and a **Play Sonos Favorite** workflow that groups selected rooms, loads a saved favorite, optionally sets each room's volume, and starts playback. A phone or computer does not need to stay on while the workflow runs. Speakers must already be set up, registered to the authorizing Sonos account, connected to the internet, and compatible with cloud playback. You can connect a streaming service through Sonos; a separate Serval Spotify connection is not required. ## Connect Sonos Go to **Integrations**, choose **Connect new**, and select **Sonos**. Copy the **Redirect URI** shown in the dialog. Sign into the [Sonos Developer Portal](https://developer.sonos.com/s/integrations). Under **Control Integrations**, create an integration, or open your existing draft. Enter your application details and register the exact Redirect URI from Serval. Create and save a client credential key, then copy its **Client ID** and **Client secret**. This is a Control Integration for controlling existing speakers. An event callback is not needed for this connector because it does not subscribe to Sonos events. Sonos documents that cloud control integrations may be released when ready; the separate Works with Sonos certification program is optional. See [Sonos's release guidance](https://docs.sonos.com/docs/connected-home-get-started). Enter a unique **Connection name**, such as "Office Sonos", and your **Client ID** and **Client secret**. The connection name distinguishes accounts and should stay the same when you reconnect. Select **Connect Sonos** and sign into the Sonos account that owns your office system. Approve access and return to Serval. Finish within ten minutes; otherwise start the connection again. Creating a new Sonos account does not transfer existing speakers to it. If you cannot see the office system, check which account registered it with your office administrator. Serval stores the credentials and refreshes access automatically. If the client secret changes or consent is revoked, reconnect with the current credentials. Sonos offers one scope, `playback-control-all`: read playback information, control music and volume, manage groups, and play favorites. It covers the account's authorized systems. A floor name in Serval does not limit that permission; target specific household and player IDs in your workflows. See [Sonos authorization](https://docs.sonos.com/docs/authorize). ## Check the connection and select speakers Run these read-only checks from the integration: | Check | What it tells you | | - | - | | Test Sonos Connection | Whether the API accepts the credentials and how many connected households it finds. | | List Sonos Players | Room names, primary player IDs, and household IDs. | | List Sonos Favorites | Playable favorite names, IDs, and household IDs. | None of these checks changes grouping, music, or volume. A successful credential check with zero households does not prove that your speakers are online. A **household** is a Sonos system on one network. Rooms in different households cannot be grouped together. Use the stable **player IDs** from discovery to select rooms. A room may represent bonded stereo or surround speakers; those devices follow the room's primary player. Group IDs can change when anyone regroups speakers, so the playback workflow discovers and creates its group each run. To list the whole account, query **every household**. Selecting `households[0]` only searches one system and can omit rooms and favorites from other systems. Keep household and player IDs in the result so a playback workflow can target the intended rooms. If `partial` is `true`, retry after regrouping settles before treating the room list as complete. ```typescript theme={null} import { workflow } from "serval/core"; import * as sonos from "serval/integrations/sonos"; export const main = workflow({ fn: async (_args: {}, ctx: sonos.context.SonosIntegration) => { const response = await sonos.apiRequest( { path: "/control/api/v1/households", method: "GET" }, ctx, ); const systems = []; for (const household of response.households ?? []) { const householdId = household.id; const groups = await sonos.apiRequest( { path: "/control/api/v1/households/{householdId}/groups", method: "GET", pathParams: { householdId }, }, ctx, ); const favorites = await sonos.apiRequest( { path: "/control/api/v1/households/{householdId}/favorites", method: "GET", pathParams: { householdId }, }, ctx, ); systems.push({ householdId, partial: groups.partial ?? false, rooms: (groups.players ?? []).map((player) => ({ playerId: player.id, name: player.name, capabilities: player.capabilities, })), favorites: favorites.items.map((item) => ({ favoriteId: item.id, name: item.name, })), }); } return { households: systems }; }, }); ``` ## Play a favorite when a deal closes 1. In the Sonos app, find **Eye of the Tiger by Survivor** through your connected music service. Save the playable track as a Sonos favorite and confirm that it plays on the office system. A saved radio station or multi-track playlist can continue playing beyond one song. 2. Run **List Sonos Favorites** and save the exact favorite ID. Favorites do not include non-playable pinned containers or Sonos playlists; use a playable music-service favorite. 3. Run **List Sonos Players**. Confirm which primary player IDs belong to the 25th floor and record their household ID. Select only those rooms. 4. Add **Play Sonos Favorite** to the existing Salesbricks deal-closed workflow and configure: | Input | Value | | - | - | | `householdId` | The discovered household containing the office rooms. | | `playerIds` | The explicit list of 25th-floor primary player IDs. | | `favoriteId` | The ID for the saved track. | | `volume` | `100` for the maximum allowed level on every selected player, or a lower integer from `0` to `100`. Omit to keep each player's current volume. | 5. Keep the existing webhook authentication and check that the event means the deal transitioned to closed-won. Deduplicate repeated notifications by deal/event ID and serialize runs targeting these speakers so celebrations do not interrupt each other. The Sonos workflow itself does not deduplicate Salesbricks events. 6. The installable workflow requires installer approval by default. Configure your team's approval policy for unattended deal-triggered runs, then perform a controlled playback test on the selected rooms. Playing a favorite regroups the selected rooms, replaces their queue, and starts music. It does not restore prior music, grouping, or volume afterward. Volume `100` still respects each Sonos product's configured Volume Limit. Fixed-volume outputs cannot accept a volume setting. The workflow checks that the favorite exists and all selected players belong to the household before changing anything. It loads the favorite without starting playback, sets volume if requested, rechecks group membership, and starts playback. A failure stops later steps but does not undo completed steps. Other Sonos controllers can still change a group during a run. ## API requests Use **Sonos API request** for discovery, grouping, favorites, playback status and controls, play modes, and player or group volume/mute. Authentication is supplied by Serval; never include credentials in workflow inputs. ```typescript theme={null} import * as sonos from "serval/integrations/sonos"; const systems = await sonos.apiRequest( { path: "/control/api/v1/households", method: "GET" }, ctx, ); await sonos.playFavorite( { householdId: "YOUR_HOUSEHOLD_ID", playerIds: ["YOUR_PRIMARY_PLAYER_ID"], favoriteId: "YOUR_FAVORITE_ID", volume: 30, }, ctx, ); ``` Group volume is an average across rooms. Use the playback workflow's `volume` input to set every selected room to the same level. ## Troubleshooting * **Redirect URI mismatch:** copy the current URI from Serval and register it verbatim in the Sonos app. Deployment environments have different callbacks. * **Expired authorization session:** reopen Connect Sonos and finish within ten minutes. * **No households or players:** verify the owning Sonos account, speaker internet connectivity, and cloud compatibility. Merely seeing registered products on the account website does not establish online status. * **Favorite unavailable:** list favorites again; a removed and re-added favorite may have a new ID. Confirm the music service is signed into Sonos and the content is playable in that account and region. * **Sonos is regrouping:** discovery returned an incomplete list. Wait for the groups to settle, then retry the check. * **Group changed:** another controller may have regrouped rooms. The favorite may already have replaced the queue and requested volume changes may already have been applied. These changes are not undone. Check the rooms, queue, and volumes before retrying. Avoid concurrent workflows for the same speakers. * **Fixed volume:** omit `volume` or choose players with controllable outputs. * **Authorization revoked or secret rotated:** reconnect the same Serval connection with current app credentials and approve Sonos access again. * **Refreshed credentials could not be saved:** Serval retries saving the replacement credentials. If all retries fail, reconnect the connection before running the workflow again. This connector does not add a streaming catalog search, audio hosting, Sonos event subscriptions, or automatic restoration of an interrupted queue. Music availability and service subscription requirements are controlled by Sonos and the connected music provider. # Splunk Enterprise Security Source: https://docs.serval.com/sections/integrations/splunk Connect Serval to Splunk Enterprise Security so workflows can pull findings into tickets, run searches for enrichment, and write results back. ## About Splunk Enterprise Security Splunk Cloud Platform is a log and event platform; Splunk Enterprise Security (ES) is the security app layered on top of it, where correlation searches produce **findings** — called **notable events** before ES 8. This integration connects to your stack's management port with a Splunk authentication token so workflows can read findings, run searches, and update investigations. It is named for ES because that is what it is built to work with: nearly every endpoint it exposes is an ES 8.x endpoint, and a stack without ES has almost nothing for it to read. The integration is marked **Beta** in Serval's connect UI. **Authentication:** Splunk authentication token (Bearer). Serval stores the token encrypted and sends it only to the host you configure. **Data sync:** On demand only. There is no background sync or asset ingestion. ## What this integration enables | Capability | Description | | - | - | | Enterprise Security API request | Typed access to the ES 8.x API — findings, investigations, notes, response plans, queues, risk scores, assets, and identities. | | Platform API request | Typed access to the Splunk platform API — dispatch and read search jobs, list saved searches, and read server info. | Reading findings is the path most teams start with: `GET /public/v2/findings` filters by time, urgency, status, owner, and correlation-search title, so a scheduled workflow can turn new findings into Serval tickets. ## Before you connect Splunk Cloud does not expose its REST API by default. Two prerequisites, both handled by a Splunk admin. The REST API listens on port 8089, and Splunk Cloud drops traffic from any address that is not on the stack's search-api allow list. Those packets are dropped silently rather than rejected, so requests fail as connection timeouts rather than as authentication errors. Add Serval's egress IPs using the Admin Config Service `search-api/ipallowlists` endpoint, or open a Splunk support case requesting REST API access for those addresses. Contact **[support@serval.com](mailto:support@serval.com)** for the current IP list. Splunk keeps a separate allow list per feature, so the entries have to go on **search-api** — adding them to `idm-api`, HEC, or any other list leaves port 8089 closed to Serval. Allow a few minutes for a change to propagate before re-running the health checks. In Splunk, create a dedicated user for Serval, give it a role with its own search quota, then generate a token under **Settings → Tokens**. A dedicated role keeps Serval's searches from competing with analyst searches on the same search head. Free trial Splunk Cloud accounts cannot access the REST API at all. The connection will fail regardless of credentials. The role needs read access to findings. ## Connect in Serval In Serval, add the **Splunk Enterprise Security** integration. It is labeled **Beta**. Enter your search head and management port, with no `https://` and no trailing path — for example `acme.splunkcloud.com:8089`. The port is required; the Splunk REST API is never served on 443. Paste the token you generated above. Submit the form. Serval runs three health checks (below). When editing an existing connection, leave the token field as its obfuscated placeholder to keep the stored token, or paste a new token to rotate. ## Verifying the connection Three health checks run after you connect: 1. **Get Server Info** — calls `/services/server/info` and reports the Splunk version. Failure here means the host, port, token, or IP allow list is wrong. 2. **Check Enterprise Security Version** — reads the ES app version and fails below 8.0, since the findings API this integration reads does not exist on older releases. 3. **List Findings** — reads one finding through the ES 8.x findings API, the endpoint that ticket ingestion depends on. If **Get Server Info** fails but your token is definitely valid, suspect the allow list before the credential. A token or role problem returns an HTTP error such as 401 or 403; a connection timeout means the request never reached the stack at all, which points at the network path rather than at anything you configured in Serval. ## Enterprise Security version requirement This integration requires **Enterprise Security 8.0 or later**. ES 8.0 renamed notable events to *findings* and gave them a REST surface — `GET /public/v2/findings`, plus investigations and notes — and that is what Serval reads. ES 7 has no equivalent; notables could only be read by running a search, which is why older releases are not supported. Saying "notables" does not tell you which version a stack is on. The `notable` index and the `@@notable@@` event ID format both survive into ES 8, and the term stays in common use long after the rename. The **Check Enterprise Security Version** health check reads the real version, so an unsupported stack shows up as a failed check on the integration rather than as an ingestion workflow that quietly returns nothing. ## Gotchas and troubleshooting A health check that hangs and then times out — no 401, no 403, no response at all — means the TCP connection to port 8089 never opened, and the requests are being dropped before they reach the stack. IP allowlisting resolves this in most cases: ask your Splunk admin to add Serval's egress IPs to the stack's **search-api** allow list, then re-run the checks a few minutes later. Contact **[support@serval.com](mailto:support@serval.com)** for the addresses to send them. Search jobs dispatched by Serval run on the same search head your analysts use. Give the Serval service account its own role and quota, and prefer the findings API over a search whenever it can answer the question — it costs no search slots. `GET /public/v2/findings` returns at most 100 items per call. Page with `limit` and `offset` until a short page is returned, and use the `total` field to size the work. A workflow that polls on a time watermark will see the same finding again across overlapping windows, and a re-fired correlation search reuses the same identity. Deduplicate on the finding's `event_id` before creating a ticket. Some organizations will not add a vendor's addresses to the search-api allow list. Those connections must egress from a self-hosted worker instead; contact **[support@serval.com](mailto:support@serval.com)** to set that up. The platform search API dispatches a job and returns a search ID. Poll the job until it reports done, read its results with paging, then delete the job so its dispatch directory is cleaned up rather than left to Splunk's quota reaper. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Splunk Enterprise Security integration. # Splunk Observability Cloud Source: https://docs.serval.com/sections/integrations/splunk-observability Splunk Observability Cloud (formerly SignalFx) is Splunk's metrics, APM, and alerting platform - Serval connects to your realm with an org access token so workflows can read and manage detectors, incidents, alert muting rules, events, SLOs, dashboards, and teams. ## About Splunk Observability Cloud Splunk Observability Cloud (formerly SignalFx) is Splunk's observability platform covering infrastructure monitoring, APM, synthetics, and detector-based alerting. Serval connects to a Splunk Observability Cloud organization using its **realm** (the regional instance identifier, e.g. us0, us1, eu0, jp0, au0) and an **org access token**, stored as a secret and attached to every request Serval makes on your behalf. An Instance Name distinguishes multiple connections on the same team. **Authentication:** Org access token with the API authorization scope (custom header authentication). The token is stored as a secret and injected on every request as the X-SF-TOKEN header. There is no OAuth flow and no token refresh - the token is used as-is until you rotate it by editing the connection. **Data sync:** On-demand only. Serval calls the Splunk Observability Cloud API when a workflow step runs - there is no background sync. This integration is for **Splunk Observability Cloud**, not Splunk Enterprise / Splunk Cloud Platform (the log-search and SIEM product). The two products have separate APIs and credentials. ## What the Splunk Observability Cloud integration enables | Capability | Description | | - | - | | Manage detectors | List, create, update, enable, disable, and validate detectors, and read a detector's events and incidents. | | Read and clear incidents | List active incidents (triggered alerts), read a single incident, and clear incidents. | | Manage alert muting rules | Create, read, update, delete, and end alert muting rules. | | Query events | Search custom and detector events with the events v2 API. | | Manage SLOs | Create, read, search, validate, update, and delete service level objectives. | | Manage dashboards and charts | Full CRUD on dashboards, dashboard groups, and charts. | | Manage teams | List teams, read team details, and manage team membership. | | Generic API access | Call any endpoint in the bundled spec (31 typed paths across the families above) with full control over the request. | Anything defined in the bundled families of the [Splunk Observability Cloud API](https://dev.splunk.com/observability/reference) can be accessed through Serval. Operations that Splunk restricts to **session tokens** (a logged-in admin's user token) are not supported, because Serval holds only your org access token. This mainly affects the Splunk-side Integrations API (managing Splunk's own notification integrations), org token management, and organization membership. Everything in the capability table above works with an org access token. ## Get your credentials Serval needs two pieces of information from Splunk Observability Cloud: your **realm** and an **org access token** with the API authorization scope. See [Splunk: Create and manage authentication tokens](https://help.splunk.com/en/splunk-observability-cloud/administer/authentication-and-security/authentication-tokens/org-access-tokens) for the official guide. Log in to Splunk Observability Cloud and open **Settings > View Profile > Organizations**. The realm is listed there, and it is also visible in your browser URL (e.g. app.us1.observability.splunkcloud.com means realm us1). Navigate to **Settings > Access Tokens**, select **New Token**, give it a name (e.g. "Serval Integration"), and choose the **API** authorization scope. Copy the token value. API-scoped access tokens carry an RBAC authorization role: power, usage, or read\_only. Reads work with read\_only; creating or updating detectors, muting rules, SLOs, and dashboards, and clearing incidents require the power role. Grant the token the role your workflows need. Getting the realm right matters more than anything else on this page. Your token only exists in your organization's realm, so a us1 organization's token will never work against the us0 API domain. ## Connect in Serval All three fields are required. Enter your realm identifier, e.g. "us0", "us1", "eu0", or "jp0". Serval derives the API domain from it: api.\.observability.splunkcloud.com. Anything other than a lowercase alphanumeric identifier is rejected. Paste the org access token you created. This is a password-type field. Give the connection a display name, e.g. "Production". Required to distinguish between multiple Splunk Observability Cloud connections. Click **Submit** to create the connection. Serval stores the token as a secret and verifies the connection with a health check against your realm. When editing an existing connection, any field you leave blank keeps its current value - only fields you fill in are overwritten. To rotate just the access token, fill in only that field. For security, the existing token value is never displayed in the edit form. ## Verifying the connection When the connection is created, Serval runs a health check that confirms your token is valid and your realm is reachable. The integration also includes four named health-check workflows you can run at any time: * **Validate Splunk Observability Cloud API Connection** - lists detectors to confirm the realm and token work together. * **Check Splunk Observability Incidents Access** - verifies Serval can read incidents (triggered alerts). * **Check Splunk Observability Dashboards Access** - verifies Serval can read dashboards. * **Check Splunk Observability Teams Access** - verifies Serval can read teams. ## Gotchas and troubleshooting The realm field is free text - it is not auto-detected. If your organization is on us1 but you enter us0, every API call fails authentication because your token only exists in your realm. Check **Settings > View Profile > Organizations** in Splunk Observability Cloud, or your app URL, and enter the matching realm. Serval expects an **org access token** (Settings > Access Tokens) with the API authorization scope. A User API access token (session token) also works against the API but expires and is tied to a person, so don't use one for the connection. Conversely, Splunk endpoints that demand a session token (the Splunk-side Integrations API, org token management, organization membership) are out of scope for this integration. An API-scoped access token carries an RBAC authorization role (power, usage, or read\_only). If workflows get 403s on writes - creating detectors, clearing incidents, managing muting rules - while reads work, the token likely has read\_only or usage authorization. Recreate or re-scope the token with the power role. Several retrieve endpoints (e.g. GET /v2/detector/\{id}) return 200 with an empty body instead of 404 when the object doesn't exist, and list endpoints return 200 with count: 0 for no matches. Workflows should check the response payload rather than relying on an error being thrown. Retrieve operations return at most 10,000 objects regardless of paging, even if your organization has more. Filter with the name/tag query parameters to narrow results instead of paging through everything. GET /v2/incident returns a JSON array of incidents, unlike most other list endpoints in the API which return a \{count, results} envelope. Workflows iterating incidents should handle the array shape. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Splunk Observability Cloud integration. # Spotify Source: https://docs.serval.com/sections/integrations/spotify Spotify is a music and audio streaming platform. Serval connects to it with your own Spotify Developer app so workflows can search the catalog, manage playlists, and control playback on demand. ## About Spotify Spotify is a music and audio streaming platform. Serval connects to a single Spotify account through a Spotify Developer app that you create and own - you supply the app's Client ID and Client Secret, and Serval handles the sign-in flow with Spotify. Once connected, workflows can search the Spotify catalog, read and edit playlists and the saved library, and control playback on the account's devices. Serval only ever sends this connection's token to one host: api.spotify.com. **Authentication:** OAuth 2.0 authorization code flow using your own Spotify Developer app (bring your own Client ID and Client Secret). Serval refreshes the access token automatically using the stored credentials. **Data sync:** On demand only. There is no background sync, polling, or webhooks - Serval talks to Spotify only when a workflow step runs. ## What the Spotify integration enables | Capability | Description | | - | - | | Generic API requests | A single "Spotify API request" action sends any request to the Spotify Web API, so workflows are not limited to a fixed action list. Paginated results page through with limit and offset values. | | Search the catalog | Find tracks, artists, albums, playlists, shows, episodes, and audiobooks from keyword queries - for example, turning a song name plus artist into a playable track. | | Control playback | List Spotify Connect devices, check playback state, start or resume, pause, skip, seek, set repeat and shuffle, transfer playback between devices, and set volume. Requires Spotify Premium and the Spotify app open on a device. | | Playlists and library | Read private and collaborative playlists, create and edit public and private playlists, and read or modify saved tracks, albums, episodes, shows, and audiobooks. | | Profile and listening data | Read the connected account's profile, currently playing track, recently played tracks, queue, and top artists and tracks. | | Play Song on Spotify (installable workflow) | A pre-built workflow that searches for a song and plays it on a chosen or active device. Inputs: song name (required), artist name, device name (case-insensitive match), and volume (0-100). It skips restricted devices and reports a failure if every device is restricted. | Anything defined in the [Spotify Web API](https://developer.spotify.com/documentation/web-api) can be accessed through Serval, within the permissions Serval requests (see the gotchas below). ## Get your credentials Serval does not ship a built-in Spotify app, so you first create one in the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard). The app issues the Client ID and Client Secret you will paste into Serval, and it must list Serval's Redirect URI in its settings. Open the Serval connect dialog first and copy the **Redirect URI** shown there - Spotify's app creation form asks for a Redirect URI, and this is the value to give it. Go to the [Spotify Developer Dashboard](https://developer.spotify.com/dashboard), log in with the Spotify account you want to use, and click **Create app**. Enter an app name (for example "Serval Integration") and a description. In the **Redirect URIs** field, paste the Redirect URI you copied from the Serval connect dialog. Accept the Developer Terms of Service and create the app. If you created the app before copying Serval's Redirect URI, open the app's settings, add it under **Redirect URIs**, and save. From the app's settings page, copy the **Client ID**, then reveal and copy the **Client Secret**. Spotify rejects the sign-in unless the Redirect URI registered on your app matches Serval's exactly. Always copy it from the read-only field in the connect dialog (it ends in /oauth/callback) rather than typing it by hand. ## Connect in Serval In Serval, add the Spotify integration. A dialog titled "Connect Spotify" opens. The read-only **Redirect URI** field has a **Copy** button (it shows "Copied" for a moment after clicking). The helper text reads "Add this as a Redirect URI in your Spotify app settings." - make sure that is done before continuing. Fill in **Client ID** (required) and **Client Secret** (required, masked as you type). Surrounding whitespace is trimmed automatically, and the **Connect to Spotify** button stays disabled until both fields are filled in (whitespace-only entries count as blank). If a blank value does slip through, it is rejected with "Please fill in all required fields" in the dialog, or "clientId is required" / "clientSecret is required" from the server. Click **Connect to Spotify** (the button reads "Connecting..." while in flight). You are sent to Spotify to approve the requested permissions, then returned to Serval. The connection is named after your Spotify profile's display name, falling back to the Spotify user ID if no display name is set. Finish the flow within 10 minutes of clicking **Connect to Spotify**. Pending credentials expire after exactly 10 minutes; taking longer produces "Invalid or expired OAuth state" or "OAuth session expired, please try again", and you must start the connection over. To rotate the Client ID or Client Secret later, run the connect flow again with the new values - there is no in-place credential edit for this integration. ## Verifying the connection The integration ships three health checks: * **Test Spotify Connection** - confirms Serval can authenticate with the Spotify API and reports the connected account. Success: "Successfully connected to Spotify as \[name]" ("unknown user" if the profile has no display name). Failure: "Unable to connect to Spotify. Please verify your OAuth credentials are valid and have not been revoked." * **Get Available Devices** - lists the account's Spotify Connect devices. Success: "Found \[number] device(s): \[names]". Zero devices still passes, with the message "API access verified but no devices found. Open Spotify on a device and log in to the connected account to see devices here." Failure: "Unable to list devices. Please verify your credentials have the user-read-playback-state scope." * **Play Song** - picks the active device (or the first one found) and starts real playback of "Never Gonna Give You Up" to prove end-to-end playback control. Success: "Now playing "Never Gonna Give You Up" on \[device name]". If no devices are found: "No active devices found. Open Spotify on a device and log in to the connected account, then try again." Failure: "Unable to start playback. This requires Spotify Premium and the Spotify app open and logged in to the connected account." **Play Song** has a real side effect: it starts actual playback on one of the connected account's devices. Do not run it against an account whose devices are in use. If **Test Spotify Connection** passes but **Get Available Devices** reports no devices, or **Play Song** fails, the usual cause is that no device is available: open the Spotify app on a phone, desktop, or speaker, log in to the connected account, then re-run the check. Playback additionally requires Spotify Premium. ## Gotchas and troubleshooting Spotify refuses to start the sign-in if the Redirect URI is not registered on your app verbatim. Copy it from the read-only field in the Serval connect dialog and paste it into the Spotify app's settings - do not retype it or trim it. Serval holds your pending credentials for exactly 10 minutes between submitting the dialog and Spotify redirecting back. If you pause mid-flow (for example, to edit your Spotify app's settings), you may see "Invalid or expired OAuth state" or "OAuth session expired, please try again" - just start the connection over. Play, pause, volume, transfer, and other player actions require Spotify Premium, and they only work on a device where the Spotify app is open and logged in to the connected account. Some devices (certain speakers and TVs) are "restricted" and cannot be controlled at all; the Play Song on Spotify workflow skips them and fails if every device is restricted. Running the **Play Song** check starts playback of "Never Gonna Give You Up" on an available device for the connected account. It only runs when you trigger it manually; the daily scheduled health-check sweep skips it. Avoid running it while those devices are in use. Serval stores your Client ID and Client Secret with the connection and reuses them to refresh the access token automatically. If you revoke or rotate the secret in the Spotify dashboard, token refresh stops working for existing connections. There is no in-place credential edit - reconnect through the dialog with the new credentials. Serval requests a fixed set of 13 Spotify permissions covering profile, email, playlists, library, playback, and listening history; you cannot narrow or extend them in the dialog. Calls outside that set fail with a permissions error - for example, reading followed artists or following and unfollowing artists and users needs follow permissions Serval does not request. A connection created before a permission was added to Serval's set will also fail related calls (for example, listing devices needs the playback-state permission) until you reconnect. The connection is identified by the Spotify account that approves the sign-in: it takes that account's user ID and display name, and every workflow call acts as that one user. To automate a different account, create a separate connection signed in as that account. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Spotify integration. # Stripe Source: https://docs.serval.com/sections/integrations/stripe Connect Stripe to Serval with a secret API key so workflows can look up and manage customers, payments, invoices, subscriptions, and payouts. ## About Stripe Stripe is a payments and financial infrastructure platform covering customers, charges, payment intents, invoices, subscriptions, refunds, payouts, products, prices, disputes, balance, and connected accounts. The Serval Stripe integration connects with a single secret API key and gives your workflows access to the full Stripe API - the integration can do exactly what the key you provide is allowed to do. Serval only ever sends the key to one host for this integration: api.stripe.com. **Authentication:** API key (a Stripe secret key or, recommended, a restricted key). There is no OAuth or sign-in flow. **Data sync:** On demand only. There is no background sync, no webhooks, and no preinstalled workflows - Serval talks to Stripe only when a workflow runs or a health check executes. ## What the Stripe integration enables | Capability | Description | | - | - | | Full Stripe API access from workflows | Workflows can call the entire Stripe API - customers, charges, payment intents, invoices, subscriptions, refunds, payouts, products, prices, disputes, balance, balance transactions, billing, and connected accounts. Reads and writes are both supported, limited only by what the connected key permits. | | Look up payments and customers | Read customers, charges, payment intents, invoices, subscriptions, refunds, and payouts as part of a workflow. | | Check account and balance | Retrieve your Stripe account status (including whether charges and payouts are enabled) and review balance and balance transaction activity. | | Create and update Stripe records | Create, update, and delete Stripe objects (customers, subscriptions, refunds, and more) from workflows, within the permissions of the connected key. | | Paginated list handling | Stripe returns list results one page at a time; workflows can page through large lists until Stripe reports there are no more results. | Anything defined in the [Stripe API](https://docs.stripe.com/api) can be accessed through Serval. ## Get your credentials You need one Stripe API key: either a standard secret key (starts with `sk_test_` or `sk_live_`) or - recommended for least privilege - a restricted key (starts with `rk_test_` or `rk_live_`) that grants only the resources your workflows need. Stripe's official guide is at [docs.stripe.com/keys](https://docs.stripe.com/keys), and details on how keys authenticate are in the [Stripe API authentication docs](https://docs.stripe.com/api/authentication). Go to [dashboard.stripe.com](https://dashboard.stripe.com) and sign in. Navigate to Developers, then API keys, or go directly to [dashboard.stripe.com/apikeys](https://dashboard.stripe.com/apikeys). Click **Create secret key** (or **Create restricted key** to limit permissions). Complete the email or SMS verification if prompted, and give the key a recognizable name such as "Serval Integration". Serval's four health checks read your account information, customers, charges, and balance transactions, so grant read access covering those resources if you want every check to pass. Add read and write access on any other resources your workflows will touch. Stripe shows the key only once. Copy it before leaving the page. Stripe keys are environment-specific. A `sk_test_` key sees only test data and a `sk_live_` key sees only live data. Create the key in the environment your workflows should operate on. A standard secret key grants full account access. If you only need Serval to read payment data, a restricted key keeps the blast radius small. ## Connect in Serval Add a new Stripe connection from your Serval integrations page, or from an application's API integration setup. The form has a single field, **API Key** (a password-type input with the helper text "Your Stripe API key (starts with sk\_test\_ or sk\_live\_)"). Paste the full secret or restricted key you created. The field is not marked required, so you will not see an asterisk or a "This field is required" error. Click **Connect Stripe** (or **Submit** if you are connecting through the configure dialog). If saving fails, the application setup form shows "Failed to connect service", while the configure dialog shows "Failed to install integration" (with details appended when available). On success the connection appears as "Stripe", pointed at api.stripe.com. Serval does not test or format-check the key when you save - a blank, mistyped, or truncated key saves without error. When you connect from an application's setup form, Serval automatically queues the enabled health checks right after the connection saves; review their results, or run them yourself with the **Run** button on the connection's health check section (see below). After saving, the key is displayed masked - bullet characters plus its last 4 characters. To rotate it later, click **Replace** next to the masked value (or the pencil icon on the connection's settings form) and paste the complete new key into the "Enter new value" box. Saving an update with the key field untouched or blank keeps your existing stored key, so you never need to re-enter the key just to edit the connection. If an update fails, Serval shows "Failed to update integration:" followed by details, "Failed to update configuration", or "Failed to save configuration. Please try again.", depending on which form you used. ## Verifying the connection The Stripe integration ships four health checks. Run them after connecting and after rotating the key. | Health check | What it verifies | Success message | Failure message | | - | - | - | - | | Get Stripe Account | The key is valid and Serval can retrieve your account information (account ID, whether charges and payouts are enabled). | "Successfully connected to Stripe account (ID: \[account ID])" | "Unable to retrieve Stripe account info. Please verify your API key is valid." | | List Stripe Customers | The key can list customers (samples up to 10). | "Successfully listed customers from Stripe (sample size: \[number])" | "Unable to list customers from Stripe. Please verify your API key has the required permissions." | | List Stripe Charges | The key can list charges (samples up to 10). | "Successfully listed charges from Stripe (sample size: \[number])" | "Unable to list charges from Stripe. Please verify your API key has the required permissions." | | List Stripe Balance Transactions | The key can list balance transactions (samples up to 10). | "Successfully listed balance transactions from Stripe (sample size: \[number])" | "Unable to list balance transactions from Stripe. Please verify your API key has the required permissions." | If "Get Stripe Account" passes but the list checks fail, your key is valid but restricted: it is missing read access to customers, charges, or balance transactions. Add those read permissions to the restricted key, or treat those specific failures as expected if your workflows never touch those resources. ## Gotchas and troubleshooting Neither the form nor Serval validates the key's presence or format at connect time. A blank, truncated, or wrong-environment key saves successfully and only shows up later as failing health checks. Check the health check results right after connecting - at minimum "Get Stripe Account". Click **Replace** next to the masked value (configure dialog) or the pencil icon (settings form) and paste the complete new key into the "Enter new value" box. Leaving the field untouched or blank when saving an update keeps the previously stored key, so edits to the connection never require re-entering a working key. After rotating, run the health checks to confirm the new key works. The four health checks read account info, customers, charges, and balance transactions. A restricted key missing read access to any of these reports "Please verify your API key has the required permissions" even if your actual workflows never touch those resources. Either grant the read permissions or treat those specific failures as expected. Test mode and live mode are separate worlds in Stripe. A `sk_test_` key only sees test data; a `sk_live_` key only sees live data. If workflows return data from the wrong environment, reconnect with the key for the intended environment. Serval attaches your Stripe API key only to requests bound for Stripe's official API host (api.stripe.com). Custom workflow steps must use standard Stripe API calls; a request to any other host will not carry the credential and will fail to authenticate. Stripe wraps list results in a page that includes a `has_more` flag, and the next page is requested with `starting_after` set to the last item's ID. Workflows that need a complete list must keep paging until `has_more` is false. Related objects can be included in a response using Stripe's `expand[]` query option. See the [Stripe API reference](https://docs.stripe.com/api) for details, and be aware of [Stripe's rate limits](https://docs.stripe.com/rate-limits) when paging through large lists. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Stripe integration. # Tableau Source: https://docs.serval.com/sections/integrations/tableau Connect Tableau Cloud or Tableau Server to Serval with a Personal Access Token to automate user provisioning, content access, and anything in the Tableau REST API. ## About Tableau Tableau is a visual analytics platform, available as Tableau Cloud and Tableau Server. Serval connects to one Tableau site using a Personal Access Token (PAT): you provide your Server URL, an optional Site Content URL, and the PAT name and secret. Serval never sends your PAT directly to Tableau's data endpoints - for every request, it exchanges the PAT for a short-lived session token scoped to your configured server and site. **Authentication:** Personal Access Token (PAT). Serval stores the token securely and exchanges it for a fresh, short-lived session token on every request - there is no stored session to expire or refresh. **Data sync:** On demand only - no background sync, polling, or webhooks. Workflows call Tableau at the moment they run. The installable Access Management workflows are event-driven: they run when access is granted or revoked in Serval, not on a schedule. ## What the Tableau integration enables | Capability | Description | | - | - | | Call any Tableau REST API action | Workflows can make any authenticated Tableau REST API call the connected account is allowed to make, including newer versionless features like collections, content search, and usage stats. | | Access Management workflow bundle | Installable "Access Management" bundle with two plug-and-play workflows: "Provision User to Tableau" assigns the requested Tableau site role when access is granted, and "Deprovision User from Tableau" sets the user's site role to Unlicensed when it is revoked. | | Manage site users | List and look up users on the connected site and change their site roles (requires a PAT created by a site or server administrator). | | Browse content | List collections, run content search, and read usage stats; read server info and the current session to identify the active site. | | Connection health checks | Four built-in checks exercise the connection end to end: API connectivity, session and site access, content access, and user-management permissions. | Anything defined in the [Tableau REST API](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_ref.htm) can be accessed through Serval. The integration works with both Tableau Cloud and Tableau Server, and uses Tableau REST API version 3.24 for Tableau's versioned endpoints - see the Tableau Server version note in the gotchas below. ## Get your credentials You need a Tableau **Personal Access Token (PAT)**. The PAT inherits the permissions of the Tableau account that creates it - Serval can do exactly what that account can do on the connected site. Create it while signed in as the account you want Serval to act as, ideally a dedicated service account (for example, serval-integration) with the right site role. See Tableau's [Personal Access Tokens documentation](https://help.tableau.com/current/online/en-us/security_personal_access_tokens.htm) for full details. If you plan to use user-management or the Access Management provisioning workflows, create the PAT while signed in as a **site or server administrator**. A non-admin PAT still works for content-only workflows. Sign in to Tableau Cloud or Tableau Server as the account whose permissions Serval should inherit, on the specific site you want to connect. Click your profile icon in the top-right corner and select **My Account Settings**. Scroll to the **Personal Access Tokens** section. Enter a descriptive token name (for example, serval-integration) - you will need this exact name in the Serval connect form - and click **Create Token**. Copy the **Secret** right away: Tableau shows it only once. If you lose it, revoke the token and create a new one. Use the bare host from your Tableau address bar, without https\:// or a trailing slash. Tableau Cloud pods look like 10ax.online.tableau.com or prod-uk-a.online.tableau.com; for Tableau Server, use your server's hostname. This is the slug between /site/ and the next slash in your browser URL. For example, in [https://10ax.online.tableau.com/#/site/acme-analytics/explore](https://10ax.online.tableau.com/#/site/acme-analytics/explore) the Site Content URL is acme-analytics. If you use the Default site, leave this blank. **Tableau Server only:** Personal Access Tokens are off by default on some Server deployments. A site or server administrator must enable them in site settings before you can create one. ## Connect in Serval In Serval, choose Tableau from the integrations list. The **Configure Tableau** dialog opens with four fields. Helper text: "Your Tableau server URL (without https\://). For Tableau Cloud, this is typically something like 10ax.online.tableau.com. For Tableau Server, use your server's hostname." Leaving it blank fails with "Server URL is required". Pasting a full URL still works - Serval automatically strips https\://, http\://, and any trailing slash. Helper text: "The content URL of the site to connect to. For the Default site, leave this empty. You can find this in the site URL after /site/." Helper text: "The name of your Tableau Personal Access Token. Create one in Tableau under My Account Settings > Personal Access Tokens." Leaving it blank fails with "Personal Access Token name is required". The name must match exactly what you entered in Tableau. Helper text: "The secret value of your Tableau Personal Access Token. This is shown only once when the token is created." Leaving it blank fails with "Personal Access Token secret is required". Click **Submit** to save the connection, then run the health checks below to confirm everything works. **Editing an existing connection:** leaving Server URL or Personal Access Token Name blank keeps the stored value. The Personal Access Token Secret appears masked (bullets plus the last 4 characters) - click the pencil icon to enter a new secret, or leave it untouched to keep the existing one. The PAT name is shown back in full so you can verify which token is configured. Site Content URL behaves differently: it is always saved on update, so submitting it empty explicitly switches the connection to the Default site. ## Verifying the connection The Tableau connection ships four health checks: | Check | What it verifies | | - | - | | Validate Tableau API Connection | Confirms your credentials are valid and the Tableau API is reachable. | | Check Tableau Session & Site | Confirms the PAT can sign in and the configured site is accessible. | | Check Tableau Content Access | Confirms the token can read Tableau content (collections). | | Check Tableau User Management Scope | Confirms the PAT can list site users, which user-management and provisioning workflows require. | On success you will see, respectively: "Successfully connected to Tableau API"; "Successfully accessed Tableau site "\[site content URL]"" (or "Successfully accessed the default Tableau site" for the Default site); "Successfully accessed Tableau content"; and "PAT can list site users (\[number] total)." (or "PAT can list site users."). On failure, the first three checks show: "Unable to connect to Tableau API. Please verify your credentials are valid and the server URL is correct."; "Failed to access the configured Tableau site. Please verify your site content URL and that the PAT has access to it."; and "Failed to access Tableau content. Please verify your token has read permissions." The user-management check shows "The configured PAT does not have permission to manage site users. Recreate the PAT under a site or server administrator account if user-management workflows are needed." when Tableau rejects the request for lack of permission, and "Failed to list Tableau site users while checking user-management scope." for other errors. If the first three checks pass but **Check Tableau User Management Scope** fails with the permission message, your PAT was created by a non-administrator account. Content workflows will still work, but user-management and the Access Management provisioning workflows need a PAT recreated under a site or server administrator. If the user-management check instead says "Could not look up the current Tableau site before checking user-management scope. Verify the Session & Site check passes first.", fix the Session & Site check before troubleshooting permissions. ## Gotchas and troubleshooting PAT name matching is exact, and a mismatched name is the most common cause of a 401. Tableau's own error summary and detail are surfaced verbatim, in the form "Tableau sign-in failed (HTTP 401, \[summary]): \[detail]". If Serval shows "could not reach Tableau at \[host]", the server is unreachable - check the Server URL and your network. A rare "Tableau sign-in succeeded but returned no session token" message means Tableau answered but did not issue a token; retry, and verify the token in Tableau if it persists. Tableau Cloud PATs expire if not used for 15 consecutive days, and site admins can set an overall expiry from 1 to 365 days (the default is 180 days on sites activated June 2023 or later). Continuous Serval use keeps the PAT alive, but a paused integration can let it lapse. To rotate: create a new PAT in Tableau, then edit the Serval connection and update the Personal Access Token Secret via the pencil icon (and the Personal Access Token Name if it changed). The PAT inherits its creator's permissions, and every sign-in targets the configured site. Sign-in fails if the PAT's account cannot access that site. Use a dedicated service account with the site role your workflows need; user-management and provisioning workflows require a site or server administrator account. Unlike the other fields, Site Content URL is always saved when you edit the connection. Submitting it empty is an explicit instruction to point the connection at the Default site - it does not mean "keep the current site". The connection's display name changes accordingly. Enter just the hostname, without https\:// or a trailing slash. Serval normalizes pasted full URLs automatically, but a wrong host typically surfaces as a sign-in failure showing a truncated raw response instead of a clear Tableau error message. For Tableau Server, the host must also be reachable from Serval over HTTPS (port 443). Serval calls Tableau's versioned endpoints with REST API version 3.24, including the sign-in request itself, and Tableau rejects calls that use an API version newer than the server supports. Tableau Cloud always supports this. REST API 3.24 shipped with Tableau 2024.3, a Tableau Cloud-only release, so the first Tableau Server release that supports it is 2025.1 - on older Server releases the connection fails at sign-in. See Tableau's [REST API versions](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api_concepts_versions.htm) table for the full mapping. Serval shows the PAT name back in full in the edit form so admins can verify which token is configured. Treat the name as a label, not a secret. The secret is always shown masked as bullets plus its last 4 characters. The provision and deprovision workflows have no role-mapping table: the Tableau site role is taken directly from the Serval role or entitlement name. Name your Serval roles exactly Viewer, Explorer, ExplorerCanPublish, Creator, or SiteAdministratorExplorer. Install the bundle, then select each workflow as the app's custom provisioning and deprovisioning workflow - they run on access grant and revocation and take no inputs. Provisioning never creates Tableau accounts: if the user has not signed in to Tableau at least once (for example via SSO), the workflow fails and asks for that first sign-in. Deprovisioning sets the user's role to Unlicensed only when the revoked entitlement matches their current site role, so stale or secondary grants do not strip access they still hold - and it deliberately never deletes the user (deletion fails if they own content). SSO and identity-provider group access is out of scope for both workflows and must be handled as a separate grant. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Tableau integration. # Tailscale Source: https://docs.serval.com/sections/integrations/tailscale Connect your Tailscale tailnet to Serval to manage devices, look up users and DNS settings, and audit ACL policies, auth keys, and configuration changes through workflows. ## About Tailscale Tailscale is a mesh VPN built on WireGuard that connects your organization's devices, servers, and services into a private network called a tailnet. The Serval Tailscale integration connects to the Tailscale API with an OAuth client or an API access token, giving workflows access to device management, user and DNS lookups, ACL policy review, device posture attributes, auth-key inventory, tailnet settings, and configuration audit logs. Serval only ever talks to Tailscale's official API address (`api.tailscale.com`), using the credentials you provide. A single connection ships with 15 prebuilt workflows across 3 bundles: Device Management, Network Info, and Security & Compliance. **Authentication:** Tailscale OAuth client or API access token. An OAuth client is recommended - it never expires, and Serval uses its client ID and secret to automatically mint short-lived API tokens as needed. An API access token expires after at most 90 days. Either way, Serval stores the credentials securely and attaches a Bearer authorization header to every Tailscale request your workflows make. **Data sync:** On-demand only. Serval calls the Tailscale API when a workflow or health check runs - there is no background sync, polling, or webhook ingestion. ## What the Tailscale integration enables | Capability | Description | | - | - | | Device management | List all tailnet devices (hostname, OS, IPs, online status), inspect a single device, view its advertised and enabled routes, and read its posture attributes. Write actions can authorize a device or revoke its authorization, expire a device's node key to force re-authentication, and set device tags (replacing existing tags). The three write workflows default to installer approval; reads require no approval by default. | | User lookup | List all users in your tailnet with role, status, and login information, or look up a specific user. No approval required by default. | | DNS configuration | View the tailnet's global DNS name servers and DNS preferences, including MagicDNS status. Read-only. | | Security and compliance | Pull the full ACL policy file (access rules, groups, tag owners, posture conditions), list configuration audit logs (who changed what and when), inventory all auth keys (capabilities, expiration, revocation status), and read tailnet-wide settings such as automatic updates, key duration, user approval, network flow logging, and posture identity collection. Combine the ACL policy with device posture attributes to evaluate whether a device meets posture requirements. | Anything defined in the [Tailscale API](https://tailscale.com/api) can be accessed through Serval. ## Get your credentials Serval supports two Tailscale credential types. Both must be created by a tailnet Owner, Admin, IT admin, or Network admin. For background, see Tailscale's [key and secret management documentation](https://tailscale.com/docs/reference/key-secret-management). * **OAuth client** (recommended): never expires. Serval uses it to automatically mint short-lived API tokens as needed, so there is no rotation routine to maintain. Its permissions are the scopes you select on the client. * **API access token:** expires after 1 to 90 days and can't be renewed. It inherits the permissions of the user who creates it. ### OAuth client Serval requests tokens without naming specific scopes, so every token carries all the scopes configured on the client. You decide what Serval can do in Tailscale by choosing scopes on the client at creation time. Sign in to the Tailscale admin console and open the [OAuth clients page](https://login.tailscale.com/admin/settings/oauth), under **Settings** > **Trust credentials**. Select **Generate OAuth client** and give it a recognizable description (for example "Serval Integration"). Grant at least **devices:core:read** - the connection health check reads your tailnet's device list. Then add scopes for the workflows you plan to run: * **devices:core** (write) for Authorize Device, Expire Device Key, and Set Device Tags * **dns:read** for the DNS nameserver and preference workflows * **feature\_settings:read** for Get Tailnet Settings * **auth\_keys:read** for the auth-key inventory The scope picker lists everything else - grant the scopes that cover your remaining workflows. The client secret starts with "tskey-client-" and is displayed in full only once. Copy both values now. ### API access token The token inherits the permissions of the user who creates it, so generate it from an account with the access your workflows need - one whose role can manage devices in the Tailscale admin console if you plan to use write actions like Authorize Device, Expire Device Key, or Set Device Tags. Sign in to the Tailscale admin console and open the [Keys page](https://login.tailscale.com/admin/settings/keys). Find the API access tokens section and select **Generate access token**. Give it a descriptive name (for example "Serval Integration"). Pick an expiry between 1 and 90 days. Tokens can't be renewed - when this one expires, you will generate a new one and update your Serval connection. The token starts with "tskey-api-" and is displayed in full only once. Copy it now - it can't be retrieved later. Whichever credential type you choose, you can pin the connection to a specific tailnet instead of the credential's default: copy your tailnet ID (for example "T1234CNTRL") from the [General Settings page](https://login.tailscale.com/admin/settings/general). Tailscale shows the client secret or access token exactly once. If you lose it before saving it in Serval, you will need to generate a new one. Most single-tailnet organizations can skip the tailnet ID entirely - Tailscale automatically uses the credential's default tailnet. ## Connect in Serval In Serval, open the Tailscale integration and start a new connection. Already connected and switching to an OAuth client? Don't create a second connection - open your existing Tailscale connection's settings and edit it there instead: choose **OAuth client**, paste the credentials, and save. Editing upgrades the existing connection in place, while creating a new one can leave the old credential active. Enter a label for this connection, such as "Production tailnet." Leave it blank and Serval names the connection "Tailscale." The name also serves as the connection's internal identifier, so pick a stable name up front. Choose **OAuth client** or **API access token (expires after at most 90 days)**. The form shows the credential fields for the method you pick. Paste the OAuth client's ID and its secret (the secret starts with "tskey-client-"). Both are password fields and are shown obfuscated after saving, with only the last 4 characters visible. Paste your full Tailscale API access token (it starts with "tskey-api-"). This is a password field and is shown obfuscated after saving, with only the last 4 characters visible. The field's placeholder text shows the accepted formats. Leave it blank (or enter "-") to use the credential's default tailnet. To target a specific tailnet, enter the tailnet ID from the admin console's General Settings page (for example "T1234CNTRL"). Name-style values like "example.com" only work for tailnets created before October 2025. Save the connection. The form marks the chosen method's credential fields as required, and Serval validates the values server-side too - a missing credential, or one whose prefix belongs to the other method, is rejected with a message that points at the right method. It doesn't call Tailscale at save time, so a mistyped credential only surfaces when the connection health check runs. On success you will see "Tailscale connected successfully" and Serval automatically runs the health check. If the save fails for another reason, you will see a general error such as "Failed to connect service" or a message starting with "Failed to install integration." When you edit this connection later, secrets you leave untouched are preserved - saving with a field still showing its obfuscated placeholder keeps the stored value. Paste a new value only for the credential you are rotating. To switch authentication methods, pick the new method and supply its full credentials. ## Verifying the connection After you connect, Serval automatically runs the connection health check. It asks Tailscale for the device list of your configured tailnet (or the credential's default tailnet when the Tailnet field is blank). A passing check confirms the credentials are valid and can read your tailnet's devices - for an OAuth client, that requires the devices:core:read scope. Tailscale has no Serval-specific failure messages - if the check fails, you will see the raw error returned by the Tailscale API, including the request URL, status code, and response body. As a rule of thumb: * An error mentioning 401 means the credential is no longer valid: an expired or revoked API access token, or a revoked OAuth client. Generate a new credential and update the connection. * A failed tailnet-scoped check usually means the Tailnet value is wrong. Use the tailnet ID from General Settings, or leave the field blank. A passing health check only proves read access. If the check is green but workflows like Authorize Device, Expire Device Key, or Set Device Tags fail with an error mentioning 403, the credential lacks device-management rights. For an API access token, generate a new one from an account whose role can manage devices in the Tailscale admin console. For an OAuth client, add the devices:core write scope. ## Prebuilt workflows Serval ships 15 prebuilt Tailscale workflows grouped into three bundles. Workflows that change state (authorize, expire key, set tags) default to requiring installer approval before they run; the read-only workflows require no approval by default. * **List Tailnet Devices** - list all devices, including hostname, OS, IP addresses, and online status * **Get Device** - retrieve detailed information about a specific device * **List Device Routes** - list the routes advertised and enabled for a device * **Get Device Posture Attributes** - retrieve a device's posture attributes (custom and provider-managed) used for compliance and access policy evaluation * **Authorize Device** - authorize a device, or revoke its authorization, on a tailnet that requires device authorization * **Expire Device Key** - mark a device's node key as expired, forcing re-authentication * **Set Device Tags** - set the tags used in ACL policies for a device (replaces existing tags) * **List Tailnet Users** - list all users with their role, status, and login information * **Get User** - retrieve detailed information about a specific user * **List DNS Nameservers** - list the global DNS name servers configured for the tailnet * **Get DNS Preferences** - retrieve DNS preferences, including MagicDNS status * **Get ACL Policy** - retrieve the tailnet's ACL policy file (access rules, groups, tag owners, posture conditions, network segmentation) * **List Configuration Audit Logs** - time-bounded record of configuration changes for compliance reviews and incident investigation * **List Auth Keys** - list auth keys with their capabilities, expiration, and revocation status for credential inventory and rotation audits * **Get Tailnet Settings** - retrieve tailnet-wide settings (automatic updates, key duration, user approval, network flow logging, posture identity collection) ### Compliance: ACL policy plus device posture The **Get ACL Policy** and **Get Device Posture Attributes** workflows combine to evaluate whether a device meets the posture requirements defined in your ACL: 1. Retrieve the ACL policy to see which posture conditions are defined and which grants depend on them (for example `posture:highTrust` requiring `falcon:ztaScore >= 80`). 2. Retrieve a device's posture attributes to see its current values. 3. Compare the device's attributes against the ACL conditions to determine which network grants it qualifies for. This supports compliance reviews, incident investigation, and verifying that devices meet security baselines before accessing sensitive network segments. ## Gotchas and troubleshooting When you open a saved connection, secrets - the OAuth client ID included - appear as obfuscated placeholders. Saving without changing them keeps the stored values - paste a new value only for the credential you are rotating. A blank Instance Name or Tailnet also keeps the existing value. To switch authentication methods, select the new method and supply its full credentials. One quirk: you can't clear a stored Tailnet back to blank - enter "-" to target the credential's default tailnet instead. Update failures surface as "Failed to update integration:" or "Failed to update configuration." If you connect with an API access token, plan a rotation routine: generate a new token on the Tailscale Keys page before the old one expires, then paste it into the Serval connection - other fields can stay as they are. To retire the routine entirely, edit the existing connection and switch it to an OAuth client, which never expires. Permissions differ too: an access token inherits its creator's permissions, while an OAuth client has exactly the scopes you configured on it. Read workflows need only read access, but Authorize Device, Expire Device Key, and Set Device Tags need device-management rights - for OAuth clients, the devices:core write scope. Those three write workflows default to installer approval in Serval. When the Tailnet field is blank, the connection health check uses `-`, which Tailscale resolves to the credential's default tailnet. The prebuilt tailnet-scoped workflows ask for a tailnet value on each run - entering "-" targets the credential's default tailnet, and when you do set a Tailnet on the connection, Serval makes that value available to workflow runs. For most single-tailnet setups, blank is correct. If you do fill it in, prefer the tailnet ID (for example "T1234CNTRL") from the admin console's General Settings page - legacy names like "example.com" only work for tailnets created before October 2025. There are no friendly Serval-specific error messages for Tailscale. An error mentioning 401 means an invalid, expired, or revoked credential. A 403 on write workflows means the credential lacks the rights for that action - the token's owning user can't manage devices, or the OAuth client is missing the devices:core write scope. A failed tailnet-scoped call usually means a wrong Tailnet value. Serval rejects a save missing the chosen method's credentials (Client ID and Client Secret, or the API access token) with a validation message. Saving also checks the credential prefixes: an API access token must start with "tskey-api-" and an OAuth client secret with "tskey-client-" - if the two are swapped, the validation message points you at the right method. A blank Instance Name isn't an error - Serval names the connection "Tailscale." It doesn't call Tailscale to test the values, so a mistyped credential with the right prefix is accepted at save time and only surfaces when the health check fails or the first workflow run errors with a 401. If you see that, edit the connection and paste a valid credential. The Tailscale API doesn't support pagination, so list workflows (devices, users, auth keys, audit logs) return all results in a single response. For large tailnets, expect big result sets. The audit log workflow is bounded only by the start and end times you give it. Authorizing a device, or revoking its authorization, only matters on tailnets where device authorization is required - on tailnets without that setting, it has no gating effect. Revoking authorization prevents a device from connecting. ## Additional resources Complete API reference for all Tailscale endpoints Generate OAuth clients and choose their scopes in the Tailscale admin console Generate and rotate access tokens in the Tailscale admin console *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Tailscale integration. # Tanium Source: https://docs.serval.com/sections/integrations/tanium Connect Serval to your Tanium Cloud instance to automate endpoint management across ten Tanium modules, from asset inventory to patching and threat response. ## About Tanium Tanium is an endpoint management and security platform. This integration connects Serval to your Tanium Cloud instance so workflows can query and act on your endpoints across ten Tanium modules - Core Platform, Asset, Comply, Connect, Deploy, Enforce, Integrity Monitor, Patch, Reputation, and Threat Response - all through a single connection. The integration supports Tanium Cloud only. **Authentication:** API token (Tanium Cloud). An admin supplies the customer-specific Tanium Cloud API domain and a Tanium API token; Serval stores the token encrypted and attaches it to every request on your behalf. Serval only ever sends the token to your own Tanium Cloud API host. **Data sync:** On-demand only. There is no background sync, entity ingestion, or scheduled data pull - workflows call Tanium live when they run, and credentials are injected server-side so workflow code never handles your token. ## What the Tanium integration enables One connection unlocks a dedicated API request action for each Tanium module. Each action targets its module's API directly, so workflow builders pick the module by action and never deal with module-specific URLs. | Module | Workflow action | What it covers | | - | - | - | | Core Platform | Tanium Platform API request | Platform-level operations - sessions, users, questions, sensors, packages, actions, and computer groups. | | Asset | Tanium Asset API request | Asset inventory queries - assets, attributes, and views. | | Comply | Tanium Comply API request | Compliance benchmarks, custom checks and profiles, exceptions, and vulnerability data. | | Connect | Tanium Connect API request | Data export connections, destinations, and connection runs. | | Deploy | Tanium Deploy API request | Software packages, deployment templates, and deployments. | | Enforce | Tanium Enforce API request | Policies, enforcements, antimalware scans, and device classes. | | Integrity Monitor | Tanium IM API request | File integrity monitors and endpoint labels. | | Patch | Tanium Patch API request | Patch lists, scan configurations, maintenance windows, and deployments. | | Reputation | Tanium Reputation API request | File hash reputation lookups. | | Threat Response | Tanium TR API request | Alerts, intel, live response, snapshots, and quarantine operations. | Anything these ten modules define in the [Tanium API documentation](https://developer.tanium.com/) can be accessed through Serval. ## Get your credentials You need two things: your **Tanium Cloud API domain** (in the form `-api.cloud.tanium.com`) and a **Tanium API token** created in the Tanium Console, scoped through a persona or role that grants the module permissions your workflows will use. Tanium's official guide is the [API tokens page in the Console User Guide](https://help.tanium.com/bundle/ug_platform_user_cloud/page/platform_user/console_api_tokens.html) (also available in the [Tanium Cloud Console bundle](https://help.tanium.com/bundle/ug_console_cloud/page/platform_user/console_api_tokens.html)). Sign in as a user with permission to manage API tokens. Create a role under **Administration > Permissions > Roles** that covers the Tanium modules your workflows will call, and assign it to a persona under **Administration > Permissions > Personas**. Go to **Administration > Permissions > API Tokens** and create a new API token. Add notes, choose the persona, and set an expiration. The expiration defaults to 7 days; the maximum is 365 days. Pick a duration that matches how often you are willing to rotate the token in Serval. Tanium rejects API token use from addresses outside the token's trusted IP list, so the token must permit the IPs Serval calls from. A token that works from your own machine can still fail from Serval if this list is too narrow. Copy the token immediately - Tanium shows it only once. Your API domain is the host of your Tanium Cloud instance's API endpoint, in the form `-api.cloud.tanium.com` - no `https://` and no path. This integration supports Tanium Cloud only. Self-hosted or on-prem Tanium Server addresses fail validation at connect time and are blocked from outbound access. ## Connect in Serval In Serval, choose to connect Tanium. The **API Domain** field is required (marked with an asterisk). Enter the bare hostname only, for example `acme-api.cloud.tanium.com`. The field's helper text reads "Your Tanium Cloud API domain (e.g. acme-api.cloud.tanium.com). Do not include https\://." Leaving it empty shows "This field is required". A value that is not a Tanium Cloud API hostname - including any `https://` prefix, path, or trailing slash - is rejected at submit with "Failed to install integration: Invalid API domain: invalid API domain format: expected `-api.cloud.tanium.com`". Paste the token you copied from the Tanium Console into this password field (also marked required). The helper text reads "A Tanium API token (session token) with the permissions required for the workflows you plan to run." There is no format check on this field. Click **Submit**. Serval validates the API Domain and stores your credentials encrypted. Serval does not test the token when you save - a mistyped, expired, or IP-restricted token is accepted at save time and only surfaces when the health check runs. Run it right after connecting (see below). After saving, the token is displayed masked - bullet characters plus its last 4 characters. To rotate it later, click **Replace** next to the masked value and paste the complete new token. Saving an update with the token field untouched or blank keeps your existing stored token. The API Domain stays visible in the form when you edit; clearing it fails validation instead of saving. ## Verifying the connection Serval runs one health check for Tanium: * **Test Tanium Connection** - verifies the stored API token authenticates against your Tanium Cloud API domain by looking up the current session on the Core Platform API. On success it reports "Successfully authenticated with Tanium Cloud". On failure: "Unable to connect to Tanium. Please verify your API token and API domain (e.g. acme-api.cloud.tanium.com) are correct." A passing "Test Tanium Connection" only proves the token can authenticate at the platform level. Workflows can still receive authorization errors from individual modules (Patch, Threat Response, Comply, and so on) if the token's persona lacks permissions for those modules. ## Gotchas and troubleshooting The API Domain must match `-api.cloud.tanium.com`. Self-hosted or on-prem Tanium Server addresses fail validation at connect time, and Serval's outbound host allow-list only permits customer-specific Tanium Cloud API subdomains, so other hosts are unreachable from workflows as well. The API Domain field takes a hostname only. Including `https://`, a path, or a trailing slash fails validation with "Failed to install integration: Invalid API domain: invalid API domain format: expected `-api.cloud.tanium.com`". The helper text says "Do not include https\://." Tanium API tokens default to a 7-day expiration in the console UI (maximum 365 days), and Serval does not auto-refresh them. When the token expires or is revoked in Tanium, the "Test Tanium Connection" check fails until an admin replaces the token. Set an expiration that matches your rotation cadence. Tanium rejects API token use from addresses outside the token's trusted IP list. A token that works when you test it yourself can still fail from Serval. Make sure the token's trusted IP settings allow the addresses Serval calls Tanium from. The token inherits its persona and role permissions. A token that passes the connection test can still get authorization errors from module actions (Patch, Threat Response, Comply, and others) it lacks permissions for. Grant the role permissions for every Tanium module your workflows call. Open the connection settings, click **Replace** next to the masked token value, paste the complete new token, and save. The API Domain is pre-filled and only changes if you edit it. Saving with the token field untouched or blank keeps the previously stored token. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Tanium integration. # Terraform Enterprise Source: https://docs.serval.com/sections/integrations/terraform-enterprise Connect Terraform Enterprise to manage workspaces, runs, state, policies and other resources through API workflows. ## What the integration supports The **Beta** Terraform Enterprise integration connects to HCP Terraform or your Terraform Enterprise instance using an API token. It supports API v2 read, create, update, delete and administrative operations, subject to your token's permissions and your instance's API version. The typed API covers HashiCorp's published stable schema, including projects, workspaces, runs and applies, configuration and state versions, variables, teams and access, policies, registry, stacks and administration. A generic API request action supports release-specific endpoints, JSON, text, forms and binary payloads. Separate signed-URL transfers support file uploads and downloads without sending your API token to storage services. Existing inventory actions remain available for organization metadata, projects, workspaces and recorded resource metadata. Connecting doesn't start a background sync. Resource metadata describes recorded Terraform state; use your cloud integration when you need current cloud inventory. ## Prepare access Create a dedicated API token with the permissions required by your workflows. Inventory-only workflows should use read permissions. Managing runs, variables, state, access or administration requires the corresponding vendor permissions and, for some APIs, a specific token type. Terraform Enterprise permissions are additive; check inherited access before connecting a token. Runs and applies can change cloud infrastructure. See HashiCorp's [API tokens documentation](https://developer.hashicorp.com/terraform/enterprise/users-teams-organizations/api-tokens) and [workspace permissions](https://developer.hashicorp.com/terraform/enterprise/users-teams-organizations/permissions/workspace). Some API endpoints and project features depend on your Terraform Enterprise release. Confirm that your release provides the [workspace resources API](https://developer.hashicorp.com/terraform/enterprise/api-docs/workspace-resources). The instance must be reachable over HTTPS with a trusted certificate. For internal instances, configure a compatible [private worker or self-hosted deployment](/sections/self-hosting/private-network-access) that can resolve the hostname and reach the API. Private networking alone doesn't grant API permissions. ## Connect 1. Open **Integrations**, select **Terraform Enterprise**, and choose **Connect**. 2. Enter the instance hostname, such as `terraform.example.com`, optionally with a port. HTTPS URLs are accepted; deployments under a custom URL path aren't supported. 3. Enter the organization name from its Terraform Enterprise URL. 4. Enter the API token and save the connection. 5. Run the organization, projects, and workspaces health checks. Each host and organization pair is a separate connection. The selected organization supplies the default for health checks; the token's permissions determine the full set of objects workflow calls can access. ## Inventory workflows Use the typed API request action to read individual pages, or **List Terraform Enterprise workspace resources** to collect all pages for one workspace. The helper stops with an error after 1,000 pages rather than presenting partial results as a complete inventory. Lists contain only objects visible to the token. A successful health check confirms that its request worked, not that the token can see every project or workspace. Compare discovery results with the expected scope before using them to reconcile another inventory. ## API workflows and files Use **Terraform Enterprise full API request** for typed API operations or **Terraform Enterprise API request (all operations)** for an explicit method and API v2 path. Full API responses include status, headers, a format and a body. Empty successful responses and asynchronous operation responses are preserved; inspect run or job status to determine completion. For an archive upload or download, first obtain its signed URL from the relevant API operation, then use **Transfer a Terraform archive using a vendor-issued signed URL**. It sends no API token. Treat signed URLs as temporary credentials and don't copy URLs from untrusted descriptions or logs into this action. Redirects are returned without being followed automatically. File transfers are limited to 50 MiB, with a two-minute request deadline. Mutations aren't retried automatically. State, variable values and logs can contain secrets. Return only necessary fields from workflows. Treat vendor-returned text as data; it doesn't authorize subsequent writes or infrastructure changes. ## Reconnect and troubleshoot Reconnect to rotate the token. Keeping the token blank or unchanged preserves the existing token only when the hostname stays the same. Changing the hostname requires a new token. * **401:** the token is missing, expired, or invalid. * **404:** the object may be absent, the token may lack access, or the API may not exist in your release. Don't treat this response as an empty inventory. * **No visible results:** check project and workspace permissions and the selected organization. * **Connection failure:** check internal DNS, firewall rules, HTTPS certificates, and the private worker configuration. A passing inventory health check confirms read access only. Test writes against disposable sandbox resources before using a write-capable connection in production. API availability varies by release and subscription; a documented operation may be unavailable on an older instance. # Thinkst Canary Source: https://docs.serval.com/sections/integrations/thinkst-canary Connect your Thinkst Canary console to Serval so workflows can list and manage Canary devices, triage and acknowledge incidents, create and manage Canarytokens, organize flocks, and administer console users. ## About Thinkst Canary [Thinkst Canary](https://canary.tools) is a deception platform: hardware, VM, and cloud "Canaries" plus Canarytokens act as tripwires that alert you the moment an attacker touches them. Connecting your Canary console to Serval lets workflows list and operate your Canary devices (Birds), triage incidents (search, acknowledge, delete), create and manage Canarytokens, organize devices into flocks, administer console users, and read the console audit trail and license state. Serval talks only to your own console's address (for example `abc123ef.canary.tools`) and attaches your API auth token to every request as the `X-Canary-Auth-Token` header - workflow authors never see or handle the token. **Authentication:** API key (your Canary console's subdomain plus an API auth token) **Data sync:** On-demand only. There is no background sync or scheduled polling - Serval calls the Canary API only when a workflow runs, and verifies the connection with lightweight read-only health checks. ## What the Thinkst Canary integration enables | Capability | Description | | - | - | | Device management | List all, live, or dead Canaries, filter devices, read device info and IPs, reboot or update a device, manage device notes, and handle the commissioning lifecycle (list pending, commission, assign pending, cancel, decommission). | | Incident triage | List all, acknowledged, or unacknowledged incidents, search incidents by string, logtype, or time window, fetch a single incident, look up incident history for a source IP, and acknowledge, unacknowledge, or delete incidents individually or in bulk. | | Canarytokens | List available token kinds, fetch, paginate, and search existing tokens, create new Canarytokens of any kind, enable, disable, or delete a token, and update a token's memo. | | Flock management | List flocks and their summaries, filter flocks, list a flock's devices, users, and settings, create, rename, or delete flocks, move devices between flocks, and assign flock managers and watchers. | | User management | List and filter console users, fetch a user, add, edit, enable, disable, or remove users, change access levels, assign or unassign users to flocks, and trigger password resets. | | Console resources | Ping the API, read detailed license info, and fetch the console audit trail. | | Raw API access | A flexible "Thinkst Canary API request" action covering every endpoint in the curated Canary Console v1 API surface. | The full endpoint list is documented in the [Canary API docs](https://docs.canary.tools/guide/list-of-endpoints.html). ## Get your credentials Serval needs your console's **subdomain** and an **API auth token**. Sign in to your console at `https://YOURDOMAIN.canary.tools` and go to **Settings > Global Settings > API**. If API access is disabled on the console, enable it - all API calls fail while it is off. Add a new API key. Canary API keys are created with a fixed role - **Admin**, **Analyst**, or **Read-Only** - that cannot be changed later. Pick the least-privileged role that covers what your workflows will do (Read-Only is enough for listing devices, incidents, and tokens; managing devices, tokens, users, or acknowledging incidents needs a write-capable role). It's the subdomain of your console URL: for `https://abc123ef.canary.tools` the console domain is `abc123ef`. It is also shown on the console's Settings page. ## Connect Thinkst Canary to Serval In Serval, add a new connection and choose **Thinkst Canary** (shown with a Beta label). Enter only the subdomain - `abc123ef` for `abc123ef.canary.tools`. Values containing `.canary.tools`, a scheme like `https://`, or uppercase letters are rejected. Paste the auth token you created on the console's API settings page. Serval builds your console's address from the subdomain and runs the health checks below to confirm it can reach the Canary API with your token. When you edit an existing connection, the stored token appears masked. Leave it as is to keep the existing token; to rotate it, replace the masked value with the entire new token. ## Verifying the connection The Thinkst Canary connection ships with four health checks. They also run again automatically whenever you save changes to the connection's settings. * **Validate Canary API connection** - calls the ping endpoint. On failure, verify the console domain, that the auth token is valid, and that API access is enabled on the console. * **List Canary devices** - confirms the token can read the console's devices, and reports how many were found. * **List flocks** - confirms the token can read flock summaries. * **List Canarytokens** - fetches a single page of Canarytokens to confirm token read access. ## Gotchas and troubleshooting Enter only the subdomain - `abc123ef` for `abc123ef.canary.tools`. Serval builds the full console address from it and only ever sends your token to your own console's canary.tools subdomain. A Canary API key's role (Admin, Analyst, or Read-Only) cannot be changed after it is created. If workflows need to acknowledge incidents, manage tokens or devices, or administer users and the health checks pass but those actions fail, the stored key is likely Read-Only - create a new key with a write-capable role and rotate it into the connection. Canary consoles can turn API access off entirely (Settings > Global Settings > API). If every call fails including ping, check that API access is enabled before suspecting the token. Binary endpoints (token file downloads, VM image downloads, audit-trail JSON download) are excluded from the integration's API surface - Serval's JSON request path does not support file responses. Thinkst Canary appears with a Beta label in the Serval connect catalog. Functionality described on this page is available today, but the integration's surface may still evolve. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Thinkst Canary integration. # Typeform Source: https://docs.serval.com/sections/integrations/typeform Connect Typeform to Serval with your own Typeform OAuth app so workflows can manage forms and quizzes, pull survey responses, and provision webhooks for new submissions. ## About Typeform Typeform is a conversational form and survey platform. The Serval Typeform integration lets your workflows manage forms and quizzes, pull and clean up form responses, organize workspaces and themes, upload images, and register webhooks that notify other systems about new submissions. Serval only ever talks to Typeform's official API hosts (api.typeform.com for United States accounts, api.typeform.eu for European Union accounts, plus api.eu.typeform.com for United States accounts whose responses live on Typeform's older EU responses data center). **Authentication:** OAuth 2.0 with your own Typeform app ("bring your own app"). Your team registers an app in Typeform's Developer Apps panel and supplies its Client ID and Client Secret in Serval's connect form - Serval does not operate a shared Typeform app. Once connected, Serval keeps access fresh automatically, so a healthy connection never needs periodic re-authorization. **Data sync:** On-demand only. Serval reads from and writes to Typeform exclusively when a workflow step runs. There is no background sync, no entity ingestion, and no prebuilt workflows are installed with this integration. ## What the Typeform integration enables | Capability | Description | | - | - | | Account info | Look up the connected Typeform account (name, email, language). Also used at connect time to name the connection after your account. | | Forms | List and search forms (optionally within one workspace), create new forms or quizzes, read a form's full definition, update it fully or partially, and delete forms. | | Responses | List a form's responses with rich filters (date ranges, completion status, text search, specific response IDs) and delete responses - up to 1000 per call. | | Webhooks | See the webhooks configured on a form, and create, update, read, or remove a webhook by its tag, so other systems are notified about new submissions. | | Workspaces | List and search workspaces, create new ones, read their details, modify them, and delete them. | | Themes | List the account's themes, create new ones, read, update, and delete them. | | Images | List the account's image library and upload new images from a file or a public URL. (Deleting individual images is not supported - see Gotchas.) | Anything defined in the [Typeform API](https://www.typeform.com/developers/) can be accessed through Serval. ## Get your credentials You need your own Typeform OAuth app - a Client ID and Client Secret - registered in Typeform's Developer Apps panel for the region your account lives in: [admin.typeform.com](https://admin.typeform.com/account#/section/apps) for United States accounts or [admin.typeform.eu](https://admin.typeform.eu/account#/section/apps) for European Union accounts. Typeform's registration form requires Serval's redirect URI up front, so the setup interleaves with the Serval side: start in Serval, register in Typeform, then finish back in Serval. See Typeform's [Applications guide](https://www.typeform.com/developers/get-started/applications/) for background. Open the Connect Typeform form in Serval and check the **Region**: **United States** if you sign in at admin.typeform.com, **European Union** if you sign in at admin.typeform.eu. It is preselected from your Serval region, so change it if your Typeform account lives in the other data center. The form displays the environment-specific **Redirect URI** with a copy button - copy it now, and leave this form open while you work in Typeform. Follow the **Typeform Developer Apps panel** link in the form (it points at the admin site for the region you chose), or log in at [admin.typeform.com](https://admin.typeform.com/) / [admin.typeform.eu](https://admin.typeform.eu/) and open the Developer Apps panel: click the icon drop-down next to your organization name in the upper-left corner, then **Developer Apps** under the Organization section. Click **Register a new app**. Fill in **App name** (e.g. "Serval Integration"), **App website** (cosmetic - it appears on the consent screen), **Redirect URI(s)** (paste the exact URI you copied from Serval), and **Developer email**. Click **Register app**. Typeform shows the **Client Secret** only once, at registration time. Copy it now. The **Client ID** stays visible in the panel afterward. On the new app's OAuth 2.0 scopes settings, approve every scope Serval requests: `accounts:read`, `forms:read`, `forms:write`, `images:read`, `images:write`, `themes:read`, `themes:write`, `workspaces:read`, `workspaces:write`, `responses:read`, `responses:write`, `webhooks:read`, `webhooks:write`, and `offline`. A missing scope makes the authorization step fail. The Client Secret is shown a single time. If you navigate away without copying it, you must regenerate it - which immediately invalidates the old value and breaks any Serval connection still using it. Always copy the Redirect URI from the Serval form rather than typing it by hand. It must match exactly, and it differs per environment. ## Connect in Serval In Serval, add the **Typeform** integration to open the connect form. **Region** is preselected from your Serval region (European Union on app.eu1.serval.com, United States otherwise). Set it to **United States** or **European Union** to match the admin site you sign in to. Serval sends you to that region's consent screen and only ever talks to that region's API for the life of the connection. The choice is fixed once the connection exists: when you reconnect, the region is shown read-only. To use Typeform's other data center, add a new Typeform connection. European Union connections appear in your connection list with an (EU) suffix. The read-only **Redirect URI** field shows the value to register in Typeform, with a copy button (its icon switches to a check mark once copied). Its helper text reads "Add this as a Redirect URI in your Typeform app settings." Fill in **Client ID** (required) - placeholder "Enter your Typeform Client ID". Stray whitespace is trimmed automatically. Fill in **Client Secret** (required) - a masked, password-style field with placeholder "Enter your Typeform Client Secret". Stray whitespace is trimmed automatically. Click **Connect to Typeform**. The button stays disabled until both fields are filled in; if a blank value slips through anyway, the form shows "Please fill in all required fields" and the server rejects it with "clientId is required" or "clientSecret is required". Serval sends you to Typeform's consent screen - approve it to finish. The connection is named after your Typeform account. Complete Typeform's consent screen within 10 minutes of clicking **Connect to Typeform**. The credentials you entered are held only briefly, and taking longer shows "Invalid or expired OAuth state" or "OAuth session expired, please try again" - just restart from the connect form. There is no separate edit-credentials form for this integration. Running the connect flow again with the same Typeform account refreshes its access and scopes in place and keeps your workflows wired up. A regenerated Client Secret is not yet carried over by reconnecting: to rotate the secret today, remove the connection and connect again with the new secret. ## Verifying the connection The Typeform integration includes three named health checks: * **Test Typeform Connection** - verifies Serval can authenticate by looking up the connected account, and reports it by name, email, or user ID (whichever is available first; "unknown user" if none are). On success: "Successfully connected to Typeform as \[name]". On failure: "Unable to connect to Typeform. Verify your OAuth credentials are valid, the app has the accounts:read scope approved, and the token has not been revoked." * **List Typeform Forms** - verifies form read access by listing a small sample of forms. On success: "Found \[number] form(s): \[up to 3 sample titles]." If the account has no forms yet: "API access verified but this account has no forms yet. Create a form in Typeform to start automating responses." On failure: "Unable to list forms. Verify your Typeform app has the forms:read scope approved on the OAuth scopes settings." * **List Typeform Workspaces** - verifies workspace read access by listing a small sample of workspaces. On success: "Found \[number] workspace(s): \[up to 3 sample names]." If the account has no workspaces yet: "API access verified but this account has no workspaces yet." On failure: "Unable to list workspaces. Verify your Typeform app has the workspaces:read scope approved on the OAuth scopes settings." Behind the scenes, Serval also re-verifies authentication with the same account lookup used by the first check. A failure there means the token was revoked, the app was deleted, or its scopes changed on the Typeform side. If all three checks are green but workflows later start failing, the cause is almost always on the Typeform side: the app was revoked or deleted, or its Client Secret was regenerated after you connected. Re-run the connect flow with fresh credentials to repair the connection. ## Gotchas and troubleshooting Typeform runs separate United States and European Union data centers with separate logins and separate Developer Apps panels. If you sign in at admin.typeform.eu but connected with **Region** set to **United States**, Serval sends you to the US consent screen, which knows neither your account nor your app. A connection's region cannot be changed afterwards, so add a new Typeform connection with **Region** set to **European Union**, make sure the app is registered at admin.typeform.eu, and remove the mistaken connection. An app registered in one region cannot be used for an account in the other. Serval only sends a connection's credentials to the API hosts of the region it was created in: api.typeform.com (and api.eu.typeform.com, Typeform's older EU responses data center) for United States connections, api.typeform.eu for European Union connections. A request to the other region's host fails before any credential is attached, with a message naming the host and the connection's region. Point the workflow at a Typeform connection created for that data center, or add one. Serval requests the same fixed set of 14 scopes on every connection: `accounts:read`, `forms:read`, `forms:write`, `images:read`, `images:write`, `themes:read`, `themes:write`, `workspaces:read`, `workspaces:write`, `responses:read`, `responses:write`, `webhooks:read`, `webhooks:write`, and `offline`. If any one of them is not enabled on your app's OAuth scopes settings, Typeform rejects the authorization with invalid\_scope. Enable the missing scope(s) in the Developer Apps panel and connect again. The Client ID and Client Secret you enter are held for only 10 minutes between clicking **Connect to Typeform** and returning from Typeform's consent screen. If the approval takes longer, the attempt expires. Restart the connection from the Serval connect form - your Typeform app itself is unaffected. Typeform access tokens expire after about one week by default. The `offline` scope - which Serval always requests - is what lets Serval refresh access automatically with a long-lived refresh token that lasts until revoked. If `offline` was not approved on your app when you connected, the connection breaks after roughly a week. Approve `offline` in the Developer Apps panel and reconnect. Serval stores your app's Client ID and Client Secret with the connection and uses them to refresh access. If the secret is regenerated in Typeform, refreshes fail as soon as the current access lapses. There is no separate update-credentials form, and reconnecting does not yet carry a new secret over: remove the connection and connect again with the fresh Client Secret. Typeform displays the Client Secret only once, at app registration, and Serval never reveals it back to you. If you did not copy it, regenerate it in the Developer Apps panel - note this immediately invalidates the old value and breaks any Serval connection still using it - then re-run the connect flow with the new secret. Typeform's **Register app** button stays disabled until **Redirect URI(s)** is filled in. That is why the setup starts in Serval: open the connect form first to reveal and copy the environment-specific Redirect URI, register the Typeform app with it in a second tab, then return to the still-open Serval form with your credentials. Always copy the URI from the form - it must match exactly. Connections are keyed on the Typeform account you authorize and named after it, with an (EU) suffix for European Union connections so a team holding both can tell them apart. Reconnecting with the same account - for example to approve more scopes - updates the existing connection in place and preserves the workflows wired to it (a regenerated Client Secret is the exception, see above). Reconnecting with a different Typeform account creates a separate connection instead. Workflows can list the account's image library and upload new images (from a file or a public URL), but there is no way to retrieve or delete an individual image through the integration. Remove images in Typeform directly if needed. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Typeform integration. # UKG Pro Source: https://docs.serval.com/sections/integrations/ukg-pro Connect UKG Pro (formerly UltiPro) to Serval so workflows can read employee, employment, and org data on demand through a dedicated UKG Pro service account. ## About UKG Pro UKG Pro (formerly UltiPro) is UKG's cloud human capital management suite, covering core HR, payroll, benefits, and talent. The Serval integration connects to your UKG Pro tenant through a dedicated service account, so workflows can look up employees, track new hires, job changes, and terminations, and read your company's org structure. This integration is for **UKG Pro HCM**. Kronos Workforce Central, UKG's self-hosted timekeeping suite, has its own [Kronos Workforce Central integration](/sections/integrations/kronos). UKG Pro Workforce Management (also called UKG Dimensions) has a separate API that this integration doesn't cover. **Authentication:** A UKG Pro service account using HTTP Basic authentication, plus your tenant's Customer API Key. Serval adds both to every request to your tenant. There is no OAuth flow or token refresh, so the stored password has to keep matching UKG Pro. **Data sync:** On demand only. Serval doesn't run a background sync or install pre-built workflows. All reads and writes happen inside workflow runs. Four health checks verify the connection. ## What the UKG Pro integration enables | Capability | Description | | - | - | | UKG Pro API request action | On-demand calls to UKG Pro's REST API from any workflow. Serval handles sign-in automatically. The action covers the Employee Data, Configuration Setup, Platform Configuration, and Security API families. | | Employee lookups | Person details (names, email addresses, addresses), employment details (job, status, supervisor, hire and termination dates), demographics, compensation, contacts, job history, and user-defined fields. | | Change tracking | Employee changes by employee or by date range, for joiner, mover, and leaver workflows. | | Org structure | Company details, org levels, jobs, positions, locations, and code tables. | | PTO plans | Read, create, and update employees' PTO plan records. UKG Pro applies these directly, without its approval workflow. | | Security users | UKG Pro user details and roles. | | Connection health checks | Four built-in checks that verify your credentials and the web service permissions Serval needs. | ## Get your credentials Serval connects as a UKG Pro service account. UKG Pro grants a service account access one web service at a time, and the health checks verify the minimum set listed below. For UKG's own reference, see [Web Service Account](https://developer.ukg.com/hcm/docs/web-service-account) on the UKG developer portal. You need access to **System Configuration > Security**. Go to **System Configuration > Security > Service Account Administration** and click **Add**. Give it a recognizable username, for example `serval-integration`. UKG Pro generates the password and shows it only once, so copy it before you leave the page. Give the service account the **View** role for **Company Configuration Integration**, **Employee Person Details**, and **Personnel Integration**. Add the **View** role for any other web service your workflows read, for example **Employee Compensation Details** or **Employee Contacts**. Each endpoint's reference page on the UKG developer portal names the web service it needs. Grant **Add** or **Edit** only for the specific services your workflows write to. Go to **System Configuration > Security > Web Services**. Copy the host from the service endpoint address, for example `service4.ultipro.com`, and copy the **Customer API Key**. Only grant the web services your workflows need. The service account can read or change exactly what its roles allow, and Serval can't narrow that further. ## Connect in Serval In Serval, add the **UKG Pro** integration to open the connect form. All four fields are required. The host from **System Configuration > Security > Web Services**, for example `service4.ultipro.com`. You can paste the full service address (for example `https://service4.ultipro.com/services/`), and Serval keeps only the host. Serval accepts only UKG Pro hosts: service or rental hosts on `ultipro.com`, Canadian hosts on `ultipro.ca`, and regional gateway hosts on `ukg.net`. The service account username. It can't contain a colon. The service account password UKG Pro generated. Your tenant's Customer API Key from the same **Web Services** page. When you reopen the connection to edit it, the saved password and Customer API Key appear masked. Leaving a masked field untouched keeps the stored value, so you can update the password or key on its own. The host and username identify the connection and can't be changed; to point at a different host or service account, add a new UKG Pro connection. ## Verifying the connection **Test UKG Pro Connection** fetches one company record, which confirms the host, credentials, Customer API Key, and the **Company Configuration Integration** permission. * Pass: "Successfully authenticated with UKG Pro and retrieved \[number] company record" **Read UKG Pro Person Details** reads one person record, which needs the **View** role for **Employee Person Details**. **Read UKG Pro Employment Details** reads one employment record, which needs the **View** role for **Personnel Integration**. **Read UKG Pro Org Levels** reads your active org levels, which needs the **View** role for **Company Configuration Integration**. If the connection test passes but a later check fails, your credentials are fine. The service account is missing that check's web service, and the failure message names it. ## Gotchas and troubleshooting Serval accepts only UKG Pro service hosts, because it sends your credentials to that host. Copy the host from **System Configuration > Security > Web Services** rather than your browser's address bar. The address you sign in to UKG Pro with isn't the API host. One of the username, password, or Customer API Key is wrong. Re-copy the Customer API Key from the **Web Services** page. If you no longer have the password, reset it in **Service Account Administration** and update the connection. Serval stores the password and sends it on every request. If the service account password changes in UKG Pro, edit the connection and enter the new one. List endpoints take `page` and `per_Page` query parameters and return at most 10,000 records per page. Loop on `page` until a page returns fewer records than you asked for. UKG Pro rate limits API calls but doesn't publish the limits. Space out bulk reads and retry after a short wait. UKG asks callers to query employee changes no more than eight times a day. UKG Pro sends the employee ID lookup as a POST so identifiers stay out of the request address, and it requires both the **View** and **Add** roles for **Personnel Integration**. It doesn't change any data. UKG Pro's REST API doesn't support new hires, terminations, or most employee record updates. UKG offers those only through its SOAP web services, which this integration doesn't cover. The action doesn't include UKG Pro's payroll endpoints (pay statements, direct deposit, pay registers). Contact [support@serval.com](mailto:support@serval.com) if your workflows need them. # Uyuni Source: https://docs.serval.com/sections/integrations/uyuni Connect your Uyuni server to Serval so workflows can read the Linux systems it manages — system details, DMI hardware inventory, network devices, groups, and custom values. Currently in beta. ## About Uyuni Uyuni is an open-source systems management platform for Linux estates — the upstream project behind SUSE Manager. It registers Linux servers and workstations, keeps their packages patched, and holds an inventory of what each machine is and how it is configured. Connecting Uyuni to Serval lets workflows read that inventory, so the Linux estate can feed asset records, access reviews, and endpoint-coverage reporting. The Uyuni integration is currently in **beta**. For a Uyuni server on a private network, enable **Run on self-hosted workers** for the connection and use an up-to-date worker and proxy. Both sign-in and API requests run from your network. The worker must be able to reach the server and trust its TLS certificate. Publicly reachable servers can use Serval's cloud proxy. **Authentication** Serval signs in to Uyuni's HTTP API with a username and password you provide, and stores the password encrypted. Serval reuses sessions for up to five minutes and can sign in again and retry a read request once if the session expires sooner. Workflow authors never handle the credentials. Use a dedicated Uyuni account for Serval. Everything Serval can read is bounded by that account's permissions and by the organization its systems belong to. **Data sync** The bundled ingestion workflow reads systems on the schedule you give it. Outside that, Serval calls Uyuni only at the moment a workflow step runs. ## What the Uyuni integration enables | Capability | Description | | - | - | | System inventory | List every system registered to the Uyuni server, with its check-in and registration times. | | System details | Read a system's profile name, hostname, OS release, entitlements, contact method, and lock status. | | Hardware inventory (DMI) | Read the vendor, product, board, asset, and BIOS values Uyuni collected from the machine's DMI tables. | | Network devices | Read a system's interfaces with their MAC addresses and IPv4/IPv6 assignments. | | System groups | Read the groups a system belongs to. | | Custom values | Read the custom-info values your Uyuni administrators defined on a system. | | Ad hoc API calls | Call any documented method under `/rhn/manager/api` that the configured account is allowed to use. | ## Pre-installed workflows | Workflow | Description | | - | - | | Ingest Linux Systems from Uyuni | Pulls every registered system into Serval as an asset, with its details, DMI inventory, network devices, groups, and custom values. | ## Get your credentials 1. In the Uyuni web UI, sign in as an administrator and go to **Users → Create User**. 2. Create a dedicated account for Serval and give it the roles it needs to read your systems. Read access to the systems you want ingested is enough for the bundled workflow. 3. Note the account's login and password, and your Uyuni server's hostname. ## Connect Uyuni to Serval 1. In Serval, go to **Settings → Integrations** and choose **Uyuni**. 2. Enter your **Server URL** — the Uyuni server's hostname, without `https://` and without a path (for example `uyuni.internal.example.com`, or `uyuni.internal.example.com:8443` if it listens on a non-standard port). 3. Enter the **Username** and **Password** of the account you created. 4. Optionally set **Serial number custom value**. Leave it blank unless you have read the note below. 5. Save the connection. ## Serial numbers and the DMI asset field Uyuni's DMI response has an `asset` field and no dedicated serial-number field, so Serval records `asset` as the system's serial number and marks the source as `dmi.asset`. On some hardware that value is the chassis or board **asset tag** rather than a manufacturer serial, and on some it is empty. If your machines carry their real serial in a Uyuni custom value instead, enter that custom-info key in **Serial number custom value**. Serval will prefer it when it holds a value, and record the source as `customValue` so you can tell the two apart downstream. Check a few known machines after the first ingestion. If `serialNumber` does not match what your hardware inventory says, the custom-value key is the way to correct it. ## Gotchas and troubleshooting Confirm the hostname is correct and reachable from the worker or Serval deployment serving the connection. For private servers, check that **Run on self-hosted workers** is enabled and that your worker and proxy are up to date. The Server URL field takes a hostname (optionally with a port). A value with a path is rejected when you save. Serval adds the `/rhn/manager/api` prefix itself. Uyuni scopes systems to organizations, and further by user role. If systems are missing from an ingestion while the connection looks healthy, the configured account cannot see them — check its organization and roles in Uyuni. Uyuni's HTTP API answers a rejected call with a success flag inside the body rather than an error status. Serval reads that flag and raises the failure, so a permission problem surfaces as a failed step instead of an empty result. If a step fails with a message quoting Uyuni, that message came from your server. The Uyuni integration is marked beta in the connect screen. Behavior and available capabilities may change. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Uyuni integration. # Vanta Source: https://docs.serval.com/sections/integrations/vanta Vanta is a security and compliance automation platform - connect it to Serval so workflows can read your compliance data (people, vendors, vulnerabilities, frameworks, trust centers) and upload documents to Vanta. ## About Vanta Vanta is a security and compliance automation platform covering SOC 2, ISO 27001, HIPAA, vendor risk management, and trust centers. Connecting Vanta to Serval lets workflows read your organizational data - people, vendors, vulnerabilities, frameworks, controls, documents, and trust centers - and upload documents to vendors, security reviews, and existing Vanta documents. Serval only ever sends your credentials to Vanta's own API. **Authentication:** OAuth 2.0 client credentials from a Vanta developer application. You supply a Client ID and Client Secret, and Serval exchanges them for an access token automatically on each request - you never handle tokens yourself. **Data sync:** On demand. Workflows call the Vanta API at the moment they run; there is no background sync or polling. Right after you connect, Serval runs the integration's health checks once automatically. The optional "Vanta Security Training Compliance Check" workflow runs on a daily schedule once installed, but that is a workflow you choose to enable, not a data sync. ## What the Vanta integration enables | Capability | Description | | - | - | | Vanta API access | Workflows can call any part of Vanta's API: people, vendors and discovered vendors, vulnerabilities, vulnerable assets and vulnerability remediations, controls, tests, documents, frameworks, groups, integrations, monitored computers, risk scenarios, and trust centers (including access requests, FAQs, subprocessors, and subscribers). | | Vendor lookups | List every vendor in your Vanta account (with status, inherent and residual risk levels, category, and review details), or look up a single vendor's ID by name. | | Document uploads | Upload files to a vendor, to a vendor security review, or to an existing Vanta document - either from a Serval attachment or from a file URL. Vendor and security review uploads validate the document type before anything is sent. | | Ready-made workflows | Four installable workflows ship with the integration: "List Vanta Vendors", "Get Vanta Vendor ID by Name", "Upload Document to Vanta Vendor", and "Vanta Security Training Compliance Check" - the last one runs on a daily schedule, checks that active employees have completed required security training (contractors are excluded), and sends Slack direct-message reminders after a configurable grace period. It needs a connected Slack integration in addition to Vanta. | Anything defined in the [Vanta API](https://developer.vanta.com) can be accessed through Serval. ## Get your credentials Serval connects with the Client ID and Client Secret of an OAuth application you create in Vanta's Developer Console. Vanta documents the full process in its [API access setup guide](https://developer.vanta.com/docs/api-access-setup). You need admin access to your Vanta account to create developer applications. Navigate to **Settings**, then **Developer Console**. Click **Create**, then configure it: give it a **Name** (for example, "Serval Integration"), a **Description**, and set the **App Type** to **Manage Vanta**. After the app is created, copy the **Client ID** and **Client Secret**. You'll paste both into Serval. The App Type must be **Manage Vanta**. Serval requests Vanta's full read and write scopes (vanta-api.all:read and vanta-api.all:write), which correspond to that app type - see [Vanta's permission scopes documentation](https://developer.vanta.com/docs/api-access-setup#permission-scopes). An app created with a more restrictive type does not grant these scopes, and the connection's health checks will fail. ## Connect in Serval "A friendly name for this Vanta integration instance (e.g., "Production Vanta")". This is purely a label - Vanta has no per-account instance ID, so pick whatever helps you tell connections apart. Leaving it blank shows "This field is required". "The Client ID from your Vanta OAuth application". Paste the Client ID you copied from the Developer Console. Leaving it blank shows "This field is required". "The Client Secret from your Vanta OAuth application". Paste the Client Secret. After saving, it is stored encrypted and displays masked (bullet characters plus the last 4 characters). Save the connection. Serval automatically runs the integration's health checks once so you can confirm everything works right away. Editing the connection later: the saved Client Secret displays masked, with a control to replace it. Leave it untouched - or blank after choosing to replace it - to keep your stored secret; it only changes when you enter a new value. **Client ID** and **Instance Name** come back pre-filled with their saved values and must stay filled in when saving an update, even if you're only rotating the secret. ## Verifying the connection The Vanta integration ships three health checks. They run automatically right after you connect (and again when you save changes to the connection), and can be re-run any time: **Test Vanta Connection** - verifies Serval can reach Vanta and list the people in your organization. * Success: "Successfully connected to Vanta. Found people in the organization." * Failure: "Unable to connect to Vanta. Please verify your API token is valid." **List Vanta Vendors** - confirms the connection can list your vendors, and returns a few sample vendors (name, status, inherent risk level) in the result. * Success: "Successfully listed vendors from Vanta (sample size: \[number])" * Failure: "Unable to list vendors from Vanta. Please verify your API token has the required permissions." **List Vanta Vulnerabilities** - confirms the connection can list vulnerabilities, and returns a few samples (severity, status, CVE ID) in the result. * Success: "Successfully listed vulnerabilities from Vanta (sample size: \[number])" * Failure: "Unable to list vulnerabilities from Vanta. Please verify your API token has the required permissions." A failure message mentioning permissions ("Please verify your API token has the required permissions") usually means your Vanta OAuth app was created with a more restrictive App Type than **Manage Vanta**. Recreate the app with the **Manage Vanta** type and update the connection with the new Client ID and Client Secret. ## Gotchas and troubleshooting Serval requests Vanta's full read and write scopes, which correspond to the **Manage Vanta** app type. If your OAuth app was created with a more restrictive type, those scopes are not granted and the health checks fail. Recreate the app with the **Manage Vanta** type per [Vanta's permission scopes documentation](https://developer.vanta.com/docs/api-access-setup#permission-scopes), then update the connection with the new Client ID and Client Secret. All three health-check failure messages reference "your API token", but this integration authenticates with OAuth client credentials. When a check fails, verify the **Client ID** and **Client Secret** from your Vanta OAuth application (and that its App Type is **Manage Vanta**) - there is no token to check. When editing a saved connection, Serval rejects the update if **Client ID** or **Instance Name** is empty - even if you only want to rotate the secret. Both come pre-filled with their saved values, so just don't clear them. The **Client Secret** is the only field you can leave unchanged: leaving it untouched or blank keeps the stored secret intact. The vendor lookup (used by the "Get Vanta Vendor ID by Name" workflow) tries a case-insensitive exact name match first, then falls back to partial matching. It fails when no vendor matches, and also when more than one vendor partially matches. Use a more specific name, or list all vendors and pick the exact vendor from the results. Uploads to a vendor or a vendor security review validate the document type first. Only 16 types are accepted - values such as CONTRACT, SOC2\_REPORT, PENETRATION\_TEST\_REPORT, ANSWERED\_QUESTIONNAIRE, BAA\_FILE, DPA\_FILE, ISO\_27001\_REPORT, and OTHER. An invalid type fails immediately with a message listing the valid types ("Valid types are: ..."), and no upload happens. Uploads to an existing Vanta document don't take a document type, so this check doesn't apply there. Serval automatically adds Vanta's "v1" version prefix to API request paths when it's missing, so workflow builders should write paths without it. If a request returns an unexpected "not found" error, check the resource path itself - a missing version prefix is not the cause, since Serval adds it for you. Vanta has no per-account or per-instance identifier, so Serval generates its own internal ID for the connection and uses the Instance Name purely as a display label. Renaming it later is safe and changes nothing about the connection. The upload steps that take a Serval attachment (upload to a vendor, to a security review, or to an existing document) first resolve the attachment within your Serval team before uploading it to Vanta. They need the workflow's Current Team context in addition to the Vanta connection - if a document upload fails before reaching Vanta, check that the workflow has team context available. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Vanta integration. # Verkada Source: https://docs.serval.com/sections/integrations/verkada Connect Verkada, the cloud-managed physical security platform, to Serval to automate user provisioning, access control, and camera operations through Verkada's full API. ## About Verkada Verkada is a cloud-managed physical security platform spanning cameras, door access control, alarms, guest management, and environmental sensors, all administered through Verkada Command. The Serval integration connects to your Verkada organization with an org-scoped API key and gives workflows typed access to Verkada's entire public API, plus a pre-built workflow for creating Verkada users. **Authentication:** API key. Serval stores your Verkada organization API key and exchanges it behind the scenes for short-lived API tokens (valid roughly 30 minutes), caching each token and refreshing it automatically before it expires - you never handle tokens yourself. **Data sync:** On-demand only. The integration performs no background syncing or data ingestion; workflows call the Verkada API live at run time. ## What the Verkada integration enables | Capability | Description | | - | - | | Verkada API request | Typed access to Verkada's full public API - 73 endpoints (112 operations) generated from Verkada's official API specification. | | Access control | Manage access users and groups, badge and license-plate credentials, MFA codes, entry codes, Pass app invites, profile photos, doors and access levels, exception calendars, remote and admin door unlocks, and lockdown scenarios. | | Cameras | Camera alerts, device inventory, footage links, thumbnails and streaming tokens, occupancy trends, license-plate analytics, persons of interest, video tagging, audio status, and cloud backup settings. | | Alarms, guest, and sensors | Alarm devices and sites, guest visits and deny lists, environmental sensor alerts and readings, access events, viewing stations, and the organization audit log. | | Create Verkada User (pre-built workflow) | Creates a user in your Verkada organization. Inputs: email, first name, last name, and external ID (all required), plus an optional employee ID. Installed with the integration; approvals default to installer approval. | Anything defined in the [Verkada API](https://apidocs.verkada.com/reference/introduction) can be accessed through Serval. ## Get your credentials You need an organization API key created by a Verkada org admin in Verkada Command, plus your Verkada Organization ID. Verkada's [Quick Start Guide](https://apidocs.verkada.com/reference/quick-start-guide) covers key creation in detail. In Verkada Command, go to Admin / Org Settings and open the **API & Integrations** tab. Click **+ Add**. Name the key (for example, ServalIntegration) and select the API endpoints Serval should be able to access. Pick **Read-Only** if Serval only needs to retrieve data, or **Read/Write** if workflows will create or modify anything - including the Create Verkada User workflow. Choose an expiration for the key. You will need to rotate the key in Serval before it expires. Click **Generate API** and copy the key immediately. In Command org settings, locate your Verkada Organization ID. You will enter it in the Serval connect form. Verkada shows the API key only once, at creation. If you lose it, you must generate a new key and update the Serval connection. Endpoint and permission scoping happens entirely in Verkada at key-creation time. The Create Verkada User workflow requires Read/Write scope covering Verkada's user management endpoints - a Read-Only key cannot create users. ## Connect in Serval In Serval, add a new Verkada connection. The connect form has three fields, all required and marked with an asterisk. Paste the organization API key you copied from Verkada Command. The field is masked as you type. Enter your Verkada API domain - for standard organizations this is api.verkada.com (the field's placeholder). You can enter the bare domain; https\:// is assumed. Leaving it blank shows "This field is required". Addresses starting with http\:// are rejected with "API domain must use https\:// protocol", and values that cannot be parsed fail with an error beginning "invalid API domain format". Enter your Verkada Organization ID from Command org settings. Leaving it blank shows "This field is required". The Organization ID identifies the connection in Serval - one connection per Verkada organization. Click **Submit**. If the backend rejects a value, the form shows "Failed to install integration" followed by "Invalid Verkada configuration" and the specific reason, such as "API key is required", "API domain is required", or "organization ID is required". A blank API Key is caught here, at submit time, rather than by the form itself. When you later edit the connection, the saved API key is shown masked - bullets plus its last 4 characters - with a **Replace** button. To rotate the key, click **Replace** and paste the complete new key into the "Enter new value" box. An update that leaves the API Key blank keeps the saved key, and API Domain or Organization ID left blank also keep their saved values. ## Verifying the connection The Verkada integration has no built-in health checks, so the connection's health-check panel will be empty - this is expected and does not indicate a problem. To confirm the connection works, run a workflow that performs a small read-only request against Verkada, such as listing your camera devices, and check that it returns data. If a verification read succeeds but a specific workflow step fails, check the API key's scope in Verkada Command first. Keys are restricted to the endpoints and permission level chosen at creation, so a key that can list cameras may still be unable to create users or unlock doors. ## Gotchas and troubleshooting This wrapper message means one of the three fields failed backend validation. The accompanying detail tells you which: "API key is required", "API domain is required", "API domain must use https\:// protocol", "invalid API domain format", or "organization ID is required". On a first-time connect the message is prefixed with "Failed to install integration"; on an edit it is prefixed with "Failed to update integration". Fix the named field and save again. Use api.verkada.com as the API Domain. Verkada's regional domains for EU and Australia, and the GovCloud domain, are not currently supported by the integration. See Verkada's [Service Regions](https://apidocs.verkada.com/reference/service-regions) page for background on regions, and contact **[support@serval.com](mailto:support@serval.com)** if your organization is hosted outside the default US region. Verkada API keys are scoped at creation to specific endpoints and to Read-Only or Read/Write. Calls outside the key's scope fail at Verkada regardless of how Serval is configured. In particular, the Create Verkada User workflow needs Read/Write scope covering user management. To broaden access, create a new key in Verkada Command with the right scope and update the connection. Serval exchanges your stored API key for a short-lived access token automatically, caches it, and refreshes it before it expires (tokens are valid for roughly 30 minutes). A one-off token error should resolve on the next run. Persistent authentication failures usually mean the API key itself has expired or been revoked in Verkada Command - generate a new key there and update the Serval connection. Verkada displays a generated key a single time. If it was not copied, generate a new key in Verkada Command (Admin / Org Settings, API & Integrations tab), then edit the Serval connection, click **Replace** next to the masked value, and paste the complete new key. The Organization ID identifies and names the connection inside Serval and supports one connection per Verkada organization. It is not attached to API requests - Verkada determines your organization from the API key itself. An incorrect Organization ID will not cause API errors, but it will mislabel the connection. Serval's Verkada API actions are generated from Verkada's official API specification, so only endpoints in the published [Verkada API reference](https://apidocs.verkada.com/reference/introduction) are available. If a request is rejected as unknown, confirm the endpoint exists in Verkada's current API documentation. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Verkada integration. # VMware vCenter Source: https://docs.serval.com/sections/integrations/vmware-vcenter Connect Serval to your VMware vCenter Server so workflows can look up virtual machines, read guest identity from VMware Tools, and report on placement and vSphere tags. ## About VMware vCenter VMware vCenter Server manages vSphere estates: the ESXi hosts, clusters, and virtual machines that run them. This integration connects Serval to your vCenter appliance so workflows can identify a virtual machine, read what VMware Tools reports from inside its guest, enumerate inventory for audits, and answer scope questions from vSphere tags. The integration is read-only and is marked **Beta** in the connect screen, so its capabilities and prebuilt workflows may still change. **Authentication:** Username and password for a vCenter Single Sign-On account. Serval exchanges those credentials for a session, reuses it for up to five minutes, and can sign in again and retry a read request once if the session expires sooner. Workflows never handle the credentials or the session. **Data sync:** None - everything is on demand. Serval calls your vCenter only when a workflow or health check runs. There is no background sync, no webhooks, and no data ingestion. ## What the VMware vCenter integration enables | Capability | Description | | - | - | | vCenter API request | A generic workflow action that can call any of the supported read endpoints, covering sessions, virtual machines, guest state, placement objects, and tags. | | Find Virtual Machine | Prebuilt workflow that resolves one virtual machine by name and returns its BIOS and instance UUIDs, configured guest OS, power state, the hostname and IP addresses VMware Tools reports, and its tags. Installs with no approval required. | | List Virtual Machine Inventory | Prebuilt workflow that enumerates virtual machines, optionally narrowed to a datacenter, cluster, or power state. Handles estates above vCenter's 4,000-result limit automatically. Installs with no approval required. | | List Virtual Machine Tags | Prebuilt workflow that lists the vSphere tags on one virtual machine, resolved to tag and category names. Installs with no approval required. | | List Virtual Machines By Tag | Prebuilt workflow that lists every virtual machine carrying a given tag, looked up by tag name. Installs with no approval required. | | List ESXi Hosts | Prebuilt workflow that lists ESXi hosts, optionally narrowed to a datacenter, cluster, or connection state. Installs with no approval required. | These use the vSphere Automation REST API introduced in vSphere 7.0 - see VMware's [vSphere Automation API documentation](https://developer.broadcom.com/xapis/vsphere-automation-api/latest/) for background on the underlying interfaces. This integration is read-only, and enforces it: Serval refuses any request to your appliance that is not a read, so it cannot power machines on or off, create or delete them, take snapshots, or change tags. ## Before you connect Two things about your vCenter appliance decide whether a connection can work at all. Check both before creating the account. Most vCenter appliances sit on an internal network that Serval's cloud cannot reach. Three deployments are possible: * **Appliance reachable from the internet**: connect normally, nothing extra needed. * **Self-hosted Serval deployment**: works when your deployment is configured to allow internal targets. * **Serval cloud with a self-hosted worker**: Enable **Run on self-hosted workers** for the connection. With an up-to-date worker and proxy, both the session exchange and API requests run from your network. The worker must be able to reach the appliance and trust its TLS certificate. Serval verifies the appliance's certificate against its trust store, and there is no option to skip that check or supply a private CA. A vCenter still serving the self-signed certificate it ships with will fail to connect. Replacing it with a certificate signed by a CA your Serval deployment trusts is standard vSphere practice - see VMware's guidance on replacing vCenter Server certificates. ## Get your credentials Serval needs your vCenter host and a vCenter Single Sign-On account. A read-only account is sufficient: this integration never writes. Sign in to the vSphere Client as an administrator and go to **Administration** then **Single Sign On** then **Users and Groups**. Create a user in the `vsphere.local` domain, for example `svc-serval`, and give it a strong password. Using a dedicated account rather than a person's login keeps the connection working when staff change. Go to **Administration** then **Access Control** then **Global Permissions**, add the new user, and assign the built-in **Read-only** role. Select **Propagate to children** so the permission covers every datacenter, cluster, host, and virtual machine. The tag workflows call vCenter's tagging service, which is separate from the inventory API. The **Read-only** role covers it in a default configuration; if your vCenter restricts tagging separately, grant the account read access there too. Use the hostname or IP address you use to reach the vSphere Client, without the "https\://" prefix and without the "/ui" path - for example "vcenter.example.com". ## Connect in Serval In Serval, go to the integrations page and select **VMware vCenter** (marked Beta). Enter the hostname or IP address of your appliance, for example "vcenter.example.com". Add a port only if your appliance does not serve the API on 443. Serval always connects over HTTPS. Enter the Single Sign-On account, for example "[svc-serval@vsphere.local](mailto:svc-serval@vsphere.local)", and its password. The password is stored encrypted and shown masked after saving. Saving validates the format of what you entered but does not call your appliance, because the connect screen cannot reach an internal network even when workflows can. Run the health checks afterwards to confirm the credentials work. ## Verifying the connection Four health checks run on demand and are the way to confirm a working connection: | Health check | What it proves | | - | - | | Test Connection | The credentials exchange for a vCenter session and the appliance is reachable. Needs no vCenter privilege beyond a valid login. | | List Datacenters | The account can read the inventory hierarchy. | | List Virtual Machines | Virtual machine inventory reads work, including the partitioning that gets past the 4,000-result limit. | | List Tags | The tagging service is reachable and readable. | If Test Connection passes but the others fail, the credentials are correct and the account is missing privileges. ## Gotchas and troubleshooting A virtual machine's hostname and IP addresses are reported by VMware Tools from inside the guest. vCenter itself does not know them. On a machine where Tools is not installed, not running, or the machine is powered off, the **Find Virtual Machine** workflow returns those fields empty with a reason rather than failing - so a machine that appears to have no IP address usually has no running Tools, not no network. Everything here comes from the vSphere layer, so the integration answers questions about a Windows or Linux server only insofar as that server is a virtual machine on this vCenter. A physical server, a machine on Hyper-V or Nutanix, and a cloud instance are all invisible. Within a virtual machine, the visible facts are its vSphere configuration plus what VMware Tools reports - hostname, IP addresses, detected OS, mounted filesystems. Patch level, installed software, Active Directory domain membership, logged-on users, and anything else requiring in-guest execution are not available: correlate on instance UUID with an endpoint agent or CMDB for those. Every virtual machine records the guest operating system it was configured for at creation. That value is what the machine claims, not what is booted - a machine created as Windows Server 2019 and later rebuilt as Linux still reports the original. The detected guest OS comes from VMware Tools, alongside the hostname and IP addresses. vCenter refuses any list request that would return more than 4,000 virtual machines, and its API has no way to page through results. Serval works around this by splitting the request across datacenters, and then across folders where a single datacenter is still too large. This is automatic, but it costs one call per partition, so inventory workflows are noticeably slower on very large estates. Narrowing to a datacenter or cluster makes them fast again. vCenter's name filter has no substring or wildcard form. The **Find Virtual Machine** workflow tries an exact match first and falls back to listing inventory and matching locally, which is why a partial name is slower. When a partial name matches more than one machine, the workflow reports the candidates and stops rather than guessing. Two categories can each hold a tag named "Production". **List Virtual Machines By Tag** reports the ambiguity and asks for a category rather than picking one, since the two usually mean different things. The BIOS UUID is what an agent inside the guest reports as the machine UUID, and cloning can produce duplicates. The instance UUID is unique per virtual machine within a vCenter. When correlating with a CMDB or an endpoint agent, prefer instance UUID where both systems have it. Serval exchanges the stored password for a session on demand. If the account's password is rotated or the account is disabled in vSphere, requests fail when the existing session stops working or Serval next needs to sign in. Update the password in the integration settings to restore it. The VMware vCenter connect tile is marked Beta, so the available actions and prebuilt workflows may still change. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your VMware vCenter integration. # Webex Source: https://docs.serval.com/sections/integrations/webex ## About Webex Webex is Cisco's collaboration and calling platform. Connecting Webex to Serval enables automated user provisioning and voice management: creating, updating, and removing Webex users, and assigning Webex Calling phone numbers to their profiles directly from your service desk. ## What the Webex integration enables | Capability | Description | | - | - | | User Management | Create, look up, update, and remove Webex user accounts | | Calling Enablement | Assign Webex Calling licenses and locations to users | | Phone Number Management | Assign and unassign phone numbers and extensions, list available numbers, and add numbers to locations | | Automation workflows | Automate joiner/mover/leaver flows for your voice platform | Anything defined in the [Webex People API](https://developer.webex.com/admin/docs/api/v1/people) and [Webex Calling configuration APIs](https://developer.webex.com/docs/api/v1/numbers) can be accessed through Serval. *** ## Webex Configuration Serval connects to Webex with a **Service App** — a machine account that a full administrator authorizes once for your organization. Unlike a personal OAuth integration, a Service App keeps working even if the authorizing administrator leaves or changes their password. ### Prerequisites * You must be a **Full Administrator** of your Webex organization * Your organization must have Webex Calling licenses for voice features ### 1. Create a Service App 1. Sign in at [developer.webex.com](https://developer.webex.com) and go to **My Webex Apps** (under your profile) 2. Click **Create a New App** and choose **Service App** 3. Give it a name (e.g., "Serval Integration"), an icon, and a description 4. Under **Scopes**, select: * `spark-admin:people_read` * `spark-admin:people_write` * `spark-admin:licenses_read` * `spark-admin:telephony_config_read` * `spark-admin:telephony_config_write` 5. Click **Add Service App** and save the generated **Client ID** and **Client Secret** Save the Client Secret securely — you will not be able to access it again after closing the page. ### 2. Authorize the Service App in Control Hub 1. In [Control Hub](https://admin.webex.com), go to **Management → Apps → Service Apps** 2. Find your new Service App and review the requested scopes 3. Toggle **Authorize** and save ### 3. Generate the token pair 1. Back on [developer.webex.com](https://developer.webex.com), open your Service App's page 2. In the **Org Authorization** section, select your organization, enter the Client Secret, and click to generate tokens 3. Copy the **Refresh Token** ### 4. Connect in Serval 1. In Serval, go to **Integrations** and select **Webex** 2. Enter an organization display name, the **Client ID**, **Client Secret**, and **Refresh Token** 3. Click **Connect** — Serval validates the credentials and refreshes the access token automatically from then on Webex access tokens last about 14 days and refresh tokens about 90 days; every automatic refresh renews both, so the connection stays healthy indefinitely while in regular use. *** ## Included workflows ### User management | Workflow | Description | | - | - | | Create Webex User | Create a new user account (sends an activation email) | | Get Webex User | Look up a user by email, including calling details | | Update Webex User | Update name, display name, department, or title | | Delete Webex User | Remove a user from the organization | ### Voice & phone number management | Workflow | Description | | - | - | | Enable Webex Calling for User | Assign a calling license, location, and primary number/extension in one step | | Assign Phone Number to Webex User | Add a number (and optional extension) to a calling-enabled user | | Unassign Phone Number from Webex User | Return an alternate number to the location's pool | | Get Webex User Phone Numbers | List the numbers assigned to a user | | List Webex Phone Numbers | List org numbers, filterable to available numbers or a location | | Add Phone Numbers to Webex Location | Add PSTN numbers to a location (non-integrated PSTN only) | Phone numbers in Webex belong to **locations**. A user must have a Webex Calling license and a location before a number can be assigned, and the number must already exist (unassigned) in that location. The "Enable Webex Calling for User" workflow handles all three steps together. # Workday Source: https://docs.serval.com/sections/integrations/workday Connect Serval to your Workday tenant so workflows can look up workers, manage time off and benefits, and automate HR requests through Workday's REST, WQL, and SOAP APIs. ## About Workday Workday is a human capital management (HCM) platform. The Serval Workday integration is a per-tenant connection to your Workday environment: it gives Serval workflows live access to Workday's REST sub-APIs (30+ modules including Staffing, Person, Absence Management, Payroll, and Recruiting), Workday Query Language (WQL), and ten Workday Web Services (SOAP) services. It also ships two installable workflow bundles - Worker Lookup, and Time Off & Benefits - so common HR lookups work out of the box. Every connection is specific to your tenant: the REST API Base URL, Token Endpoint, and optional user-auth endpoints all belong to your Workday environment. **Authentication:** Service account via OAuth 2.0 refresh-token grant, tied to an Integration System User (ISU) and an API Client for Integrations registered in your Workday tenant. An optional, feature-flagged per-user (3-legged) OAuth path lets certain actions run as the end user. **Data sync:** On-demand only. Nothing is mirrored into Serval on a schedule - workflow actions and health checks call Workday live, and a fresh access token is obtained from your tenant's token endpoint for every call. ## What the Workday integration enables | Capability | Description | | - | - | | REST requests across 30+ Workday modules | Typed request actions for Workday's REST sub-APIs, including Staffing, Person, Absence Management, Compensation, Payroll, Global Payroll, Recruiting, Talent Management, Time Tracking, Expense, Procurement, Projects, Custom Reports (RaaS), Workday Help, Prism Analytics, Student modules, Workday Connect messaging, and more. | | WQL (Workday Query Language) queries | Run WQL queries against standard data sources such as allWorkers, allActiveWorkers, and allActiveAndTerminatedWorkers - used by worker lookups and the WQL health check. | | SOAP (Workday Web Services) requests | Typed SOAP actions for ten services: Staffing, Human Resources, Absence Management, Benefits Administration, Compensation, Integrations, Payroll, Performance Management, Recruiting, and Time Tracking. Common operations include Get\_Workers, Hire\_Employee, Terminate\_Employee, Get\_Job\_Postings, and Get\_Organization\_Goals. | | Worker lookup and change-request helpers | Higher-level actions such as find worker by email or employee ID, find eligible absence types, get organization goals, and update a worker's primary home phone number or home address (including adding a home phone number where none exists). | | Worker Lookup bundle | Six prebuilt workflows: Search for Workday Worker by Name, Get Workday Worker ID by Email, Get Workday Worker, List Workday Workers, Get Workday Worker Absence, and Get Workday Holiday Events. All default to no-approval. | | Time Off & Benefits bundle | Five prebuilt workflows: Get User PTO Balance from Workday, Get Workday Eligible Absence Types, Lookup Workday Team Member Time Off Requests, Get Workday Worker Benefit Elections, and Request Time Off in Workday. The reads default to no-approval; Request Time Off in Workday writes back to Workday and defaults to installer-approval. | | Write workflows | Two additional prebuilt write workflows: Update Workday Worker Primary Home Phone Number and Update Workday Worker Primary Home Address. Both default to installer-approval. | | Per-user (as-user) requests | When the optional per-user OAuth app is configured, user-scoped variants of the request actions call Workday as the acting user with their own credential, so Workday records that person as the initiator and applies their own permissions. Available for the Request, Staffing, Absence Management, Person, and Business Process REST sub-APIs, and the Human Resources and Staffing SOAP services. The user must have connected their personal Workday account first. | Anything defined in the [Workday API](https://community.workday.com/sites/default/files/file-hosting/restapi/index.html) can be accessed through Serval. ## Get your credentials Setting up the connection requires a Workday administrator. You will create an Integration System User (ISU), grant it the security it needs, register an API Client for Integrations, and generate a refresh token. Workday's official API reference is the [Workday REST Services Directory](https://community.workday.com/sites/default/files/file-hosting/restapi/index.html). In Workday, search for **Create Integration System User** and create the ISU (for example, `ServalIntegration`). The password cannot contain the characters `&`, `<`, or `>`. Search for **Maintain Password Rules** and add the ISU to **System Users exempt from password expiration**. Search for **Create Security Group**, choose the type **Integration System Security Group (Unconstrained)** (for example, `Serval Integration Group`), and add the ISU under Integration System Users. Search for **Maintain Permissions for Security Group** (Operation: Maintain; Source Security Group: your group) and add the Domain Security Policies your use case needs. The minimum for worker reads is **Worker Data: Public Worker Reports** with Get Only access. Only grant the permissions you actually need. Every Serval action runs with the ISU's permissions. Search for **Activate Pending Security Policy Changes** and confirm. Search for **Manage Authentication Policies**, add your security group to an authentication rule with Allowed Authentication Types **User Name Password** or **Any**, then run **Activate All Pending Authentication Policy Changes**. Search for **Register API Client for Integrations** - not **Register API Client**, which is a different task used only for the optional per-user flow below. Set a **Client Name** (for example, `Serval Workday API Client`), check **Non-Expiring Refresh Tokens**, leave **Disabled** unchecked, fill in **Scope (Functional Areas)** (see below), and save. Copy the **Client ID** and **Client Secret**. This task has no grant-type field and no confidential-versus-public choice: an integrations client is always a confidential client using the refresh-token grant. Leave **Enforce Customized Access Token Expiry** unchecked and **Refresh Token Timeout** at `0`. **Scope (Functional Areas)** is required. The prompt shows **No matches found** until you type into it - it does not list every area up front. Add the areas your use case needs: | To use | Add the scope | | - | - | | Worker and supervisory-org lookups, SOAP `Get_Workers` (three of the four health checks) | **Staffing** | | The Execute WQL Query health check, and finding a worker by email or employee ID | **System - Workday Query Language** | | Time off balances, eligible absence types, Request Time Off | the absence area - search "absence", then "time off" | | Worker benefit elections | **Benefits Administration** | | Updating a worker's primary home phone number or home address | **Contact Information** and **Personal Data** | | Compensation, Recruiting, Performance Management, or Time Tracking actions | that functional area by name | Also add **Integration** and **System** for the baseline integration domains, and check **Include Workday Owned Scope** if you need core Workday domains that aren't part of any functional area. Scope is not a substitute for permissions - it caps which functional areas the access token can reach, and the ISU still needs the domain security policies granted in the earlier steps. Both must allow a call for it to succeed. The Client Secret may only be shown once. Copy it immediately and store it securely. Search for **Manage Refresh Tokens for Integrations**, select your API client, add the ISU as the Authorized User, choose an expiration, generate, and copy the **Refresh Token** - it is not viewable again. Choose **Never** for expiration if your policy allows. Every Serval-to-Workday call depends on this refresh token; if it expires, all Workday actions stop working until you update the connection. Search for **View API Clients**, open your API client, and copy two values: the **Workday REST API Endpoint** (for example, `https://impl-services1.wd12.myworkday.com/ccx/api/v1/` - this maps to Serval's **REST API Base URL** field) and the **Token Endpoint** (for example, `https://impl-services1.wd12.myworkday.com/ccx/oauth2//token` - this maps to Serval's **Token Endpoint** field). Copy both verbatim. Workday includes the tenant in the token endpoint path, and the REST endpoint may include a version segment (`/ccx/api/v1/`) - Serval reads only the host and the final path segment, so either form works. Search for **Public Web Services**, locate the SOAP service you use (for example, **Human Resources (Public)**), choose **Web Services → View WSDL**, and copy the service URL for Serval's **WSDL URL** field. Your tenant name appears in your Workday URL (for example, `https://wd2-impl.workday.com//d/home.html`), or ask your administrator. The per-user path is purely additive - the service account keeps working unchanged if you skip this. It lets workflow actions run as the acting end user instead of the ISU, so Workday records that person as the initiator and applies their own permissions and business process rules. This requires a **second** OAuth API client, registered with a different Workday task than the service account's. Search for **Register API Client** - the task without "for Integrations". Set a **Client Name**, then: * **Client Grant Type**: **Authorization Code Grant** only * **Access Token Type**: **Bearer** * **Redirection URI**: Serval's callback for this flow (see the next step) * **Public client**: leave unchecked. Serval authenticates with the client secret and sends no PKCE `code_challenge`, so a public client cannot complete the code exchange * **Non-Expiring Refresh Tokens**: check it if your policy allows, otherwise users must re-consent when their refresh token expires * **Scope (Functional Areas)**: required, and it caps every user's session (see below) Copy the **Client ID** and **Client Secret** on save. The secret is shown once; if you lose it, use the client's related action **API Client → Generate New Client Secret**. For Serval's main US cloud, register this exact value: ``` https://svflow-auth-config.api.serval.com/workday/user/oauth/callback ``` If your Serval tenant is on the EU shard, use `https://api.eu1.serval.com/v1/svflow-authconfig/workday/user/oauth/callback` instead (ask [support@serval.com](mailto:support@serval.com) if you're unsure which region you're on). Workday requires an exact redirect-URL match, so register it verbatim - no trailing slash and no extra path. Serval requests no `scope` parameter when it sends a user to Workday, so the functional areas registered on this client are a hard ceiling on what any user's session can reach - regardless of what that person can do when signed into Workday directly. Add the functional areas covering the actions you intend to run as the user, and nothing more. Changing this client's scope later requires each connected user to reconnect: OAuth binds scope at consent time, so existing per-user credentials keep the scope they were granted. From **View API Clients**, copy the **Authorization Endpoint** (for example, `https://impl.wd12.myworkday.com//authorize`) into Serval's **User-Auth Authorize Endpoint** field. There is no separate user-auth token endpoint - this flow reuses the **Token Endpoint** already configured for the service account. On the existing Workday connection, fill in **User-Auth OAuth Client ID**, **User-Auth OAuth Client Secret**, and **User-Auth Authorize Endpoint**, then save. The service-account fields stay as they are - a connection cannot be per-user only. ### How users connect Users do not need access to integration settings, and you do not need to provision anyone in advance. Consent is requested the first time it's needed: 1. A user triggers a workflow that runs an action as them. 2. Serval checks before the run starts whether they've connected their Workday account. If they haven't, the run stops - it never falls back to the ISU. 3. They receive a link to connect (in a ticket or chat, the Serval agent posts it to them), consent through your tenant's standard Workday sign-in, and see a confirmation. 4. They trigger the workflow again, and it runs under their own credential from then on. If a workflow needs more than one connection, all of them are requested at once. Connecting does not automatically resume the failed run. Administrators can connect or test their own account from the **Your connection** section on the integration's API Integration tab. The per-user path is currently in limited release. The User-Auth fields only appear on the connect form once it's enabled for your team - contact **[support@serval.com](mailto:support@serval.com)** to turn it on. Workday OAuth is per-tenant - there is no global client, so the config lives on your connection. ## Connect in Serval In Serval, add a new Workday connection. The form collects your tenant details, OAuth credentials, and SOAP fields. **Tenant Name** (required) - for example, `mycompany`. Saving without it fails with: `Invalid Workday configuration: tenant name is required` **Client ID** (required), **Client Secret** (required), and **Refresh Token** (required) - from the API client and refresh token you created in Workday. All three are stored encrypted. Missing values fail with, respectively: `Invalid Workday configuration: client ID is required`, `Invalid Workday configuration: client secret is required`, and `Invalid Workday configuration: refresh token is required` **REST API Base URL** (required) - for example, `https://wd2-impl-services1.workday.com/ccx/api/mycompany`. It must start with `https://` and contain `/ccx/api/` - Serval derives every REST and SOAP endpoint from this one URL. Errors on create: `Invalid Workday configuration: REST API base URL is required` or `Invalid Workday configuration: REST API base URL must start with https://`. When editing: `REST API base URL must start with https://` or `Invalid REST API base URL format` **Token Endpoint** (required) - for example, `https://wd2-impl-services1.workday.com/ccx/oauth2/token`. Must start with `https://`. Errors on create: `Invalid Workday configuration: token endpoint is required` or `Invalid Workday configuration: token endpoint must start with https://`. When editing: `Token endpoint must start with https://` or `Invalid token endpoint format` **WSDL URL** (required by the form) - for example, `https://wd2-impl-services1.workday.com/ccx/service/amn1/Human_Resources/v28.2`. **ISU Username** (required by the form) - for example, `ServalIntegration`. **ISU Password** (required by the form) - stored encrypted. These three fields are required by the form but are not validated when the connection is saved, and they are not used to make requests - SOAP endpoints and authentication are derived from the REST API Base URL and OAuth credentials (see Gotchas and troubleshooting below). **Connection Name** (optional) - for example, `HR Service Account`. This is how the connection appears in Serval. Leave it blank to use the tenant name and ISU Username, for example `mycompany (ServalIntegration)`. Serval identifies a Workday connection by its tenant and ISU Username, so each Integration System User gets its own connection and a team can connect several service accounts to the same tenant without any extra setup. If the per-user OAuth feature is enabled for your team, three optional fields appear: **User-Auth OAuth Client ID**, **User-Auth OAuth Client Secret**, and **User-Auth Authorize Endpoint** (placeholder `https://wd2-impl-services1.workday.com//authorize`). Leave them blank if this connection only uses the service account. These endpoints are validated when the user OAuth flow runs (not at save): both the authorize and token endpoints must be HTTPS URLs on `*.workday.com` or `*.myworkday.com`. Save, then run the health checks below to verify everything works. Edit behavior differs by field type. The six secret fields (Client ID, Client Secret, Refresh Token, ISU Password, User-Auth OAuth Client ID, User-Auth OAuth Client Secret) display obfuscated (•••• plus the last 4 characters) and **keep their stored value** if you leave them blank or unchanged, as does Connection Name. The six non-secret fields (Tenant Name, REST API Base URL, Token Endpoint, WSDL URL, ISU Username, User-Auth Authorize Endpoint) are saved **exactly as submitted** - clearing one of them clears the stored value. The edit form prefills current values; don't delete them unless you mean to. The connection's display name updates only when you submit a new, non-empty Connection Name, and its API domain only when you submit a new, non-empty REST API Base URL. The connection's identity in Serval never changes on edit. ## Verifying the connection Four health checks verify the connection on demand: **List Workday Workers** - lists up to 10 workers through the Staffing API using the service-account credential, verifying REST connectivity and worker-read permissions. * Success: `Successfully listed [number] workers` * Failure: `Unable to list workers.` - on permission errors (401/403) it adds ` The API credentials may be invalid or the integration user may not have the required permissions.`; on Workday server errors (500/502/503) it adds ` Workday returned a server error. This is likely a temporary issue - please try again later.` **List Supervisory Organizations** - lists up to 5 supervisory organizations through the Staffing API, verifying org-structure read access. * Success: `Successfully listed [number] supervisory organizations` * Failure: `Unable to list supervisory organizations.` - with the same conditional permission and server-error suffixes as above. **Execute WQL Query** - runs a one-row WQL query (`SELECT worker, fullName FROM allWorkers LIMIT 1`) to verify Workday Query Language access. * Success: `Successfully executed WQL query (returned [number] result(s))` * Failure: `Unable to execute WQL query.` - with the same conditional permission and server-error suffixes as above. **SOAP API - Get Workers** - calls the Staffing SOAP service's Get\_Workers operation requesting a single worker, verifying SOAP connectivity. * Success: `Successfully connected to Workday SOAP API (retrieved [number] worker(s))` * Failure: `Unable to connect to Workday SOAP API.` - with SOAP-specific suffixes: on authentication errors, ` The ISU username or password may be invalid. Please check your integration configuration.`; on forbidden errors, ` The ISU does not have permission to access the Staffing SOAP service. Please check Workday security group assignments.`; on WSDL errors, ` Could not connect to the WSDL URL. Please verify the WSDL URL is correct and accessible.`; on connection errors, ` Could not connect to Workday. Please verify the WSDL URL and network connectivity.`; otherwise the generic permission and server-error suffixes. If the two REST checks and the SOAP check pass but **Execute WQL Query** fails, your tenant likely has WQL disabled - the connection itself is fine. Worker lookups that depend on WQL (finding a worker by email or employee ID) will keep failing until WQL is enabled in your tenant, or those workflows are switched to the equivalent SOAP-based lookup (the Get\_Workers operation). ## Gotchas and troubleshooting Serval fetches a fresh access token from your Token Endpoint on every single call - there is no token caching for the service account. If Workday reports that it rejected the OAuth client ID or client secret, update the connection with the current client credentials. If Workday reports that it rejected the refresh token, generate a new refresh token and update the connection. Use non-expiring refresh tokens where your policy allows. S22 means Workday authenticated the call and then refused it, so the credentials, token endpoint, and REST API Base URL are all fine. Two separate gates must both allow a call, and a 403 means one of them doesn't: 1. **The API client's Scope (Functional Areas)** - the ceiling on which functional areas that client may ever touch. 2. **The account's domain security policies** - the ISU's security group for service-account calls, or the individual's own Workday permissions for per-user calls. Scope never grants access; it only caps it. Work through these in order: * **Check the right client.** Service-account calls use the client from **Register API Client for Integrations**; per-user calls use the separate **Register API Client** one. Each has its own scope, and it is easy to widen one while the other is the cause. * **Match the scope to the endpoint's domain, not its URL.** A functional area is a bundle of security domains, and the domain securing an endpoint often belongs to a different area than the REST path suggests - `/supervisoryOrganizations` is secured by organization data, not Staffing. The endpoint's "Secured by" line in the [Workday REST Services Directory](https://community.workday.com/sites/default/files/file-hosting/restapi/index.html) is authoritative. * **Activate pending security changes.** Domain policy edits do not take effect until you run **Activate Pending Security Policy Changes**. * **Reconnect after a per-user scope change.** Scope is bound at consent time, so users who connected before the change keep the old scope until they reconnect. Service-account calls need no equivalent step - Serval fetches a fresh access token on every call, so scope changes there apply immediately. A useful signal: if the SOAP and WQL health checks pass while the REST ones fail, look at scope first. If everything fails, look at the ISU's domain security policies. Some Workday tenants have WQL disabled. A failing Execute WQL Query check does not necessarily mean the connection is broken - if the REST and SOAP checks pass, the connection works. However, worker lookups that depend on WQL (such as finding a worker by email or employee ID) will not succeed until WQL is enabled, or those workflows are adapted to use the SOAP Get\_Workers operation instead - the switch is not automatic. The backend only validates Tenant Name, REST API Base URL, Token Endpoint, Client ID, Client Secret, and Refresh Token at save time. WSDL URL, ISU Username, and ISU Password are required by the form but are stored without validation and never used when requests are made - a typo in them neither blocks saving nor breaks the SOAP check. When the SOAP check fails, look at the values that actually drive SOAP calls: the **REST API Base URL** (every SOAP endpoint is derived from it - see the next accordion), the OAuth credentials (Client ID, Client Secret, Refresh Token), and the ISU's security group permissions in Workday (the health check needs access to the Staffing SOAP service). Although the SOAP failure guidance mentions the ISU username and password, live SOAP requests authenticate with the same OAuth bearer token as REST requests - the ISU matters because it underpins the refresh token and the permissions model, not through the stored ISU Password field. Every REST and SOAP endpoint Serval calls is derived from the REST API Base URL at request time - the stored WSDL URL field is not used to build request URLs. The base URL must contain `/ccx/api/`; if it doesn't, SOAP endpoint derivation fails with an `Unexpected API domain format` error. If anything looks wrong across the board, verify this field first against the **View API Clients** task in Workday. Only the secret fields and Connection Name keep their stored value when left blank during an edit. The non-secret fields - Tenant Name, REST API Base URL, Token Endpoint, WSDL URL, ISU Username, and User-Auth Authorize Endpoint - are written exactly as submitted, so submitting one of them empty blanks it out (clearing the Token Endpoint, for example, breaks every call). The connection's display name and API domain are only updated when you submit a new, non-empty value. The edit form prefills current values; leave them in place unless you intend to change them. Serval identifies a Workday connection by its tenant and **ISU Username**, so adding a second Integration System User for the same tenant creates a second connection with its own credentials and needs no extra setup. Submitting the same tenant and ISU Username again updates that connection's credentials instead of adding a new one. Unnamed connections are labeled ` ()`; set a **Connection Name** on each to tell them apart more easily. If you created the app instance ahead of time (for example through Catalyst) and then connect Workday credentials to it, the credentials attach to that app instance and its existing name and external instance ID are kept. The three User-Auth fields only appear once the per-user OAuth feature is enabled for your team. The user-auth app is a separate Workday OAuth API client (Authorization Code grant) stored on the service-account connection - leaving the fields blank changes nothing about the service account. Both the authorize and token endpoints are validated when the OAuth flow runs (not when you save): they must be HTTPS on `*.workday.com` or `*.myworkday.com`, since the client secret travels to these URLs. If someone tries to connect their personal Workday account before the app is configured, the attempt fails with: `workday connection has no user-auth OAuth app configured (set the User-Auth OAuth Client ID/Secret)`. Other endpoint errors include: `workday connection is missing the user-auth authorize/token endpoint`, `workday user-auth authorize endpoint "" must use https`, and `workday user-auth authorize endpoint "" is not an allowed workday host`. An as-user workflow action fails at run time if the acting user has not connected their personal Workday account. User tokens are refreshed only near expiry and always against the exact connection that minted them. Earlier versions of this documentation described SOAP support as "coming soon" and used different field names. SOAP is fully supported today, with ten Workday Web Services available. The current form labels are **REST API Base URL** (previously described as "REST API Endpoint") and **WSDL URL** (previously "Web Services Endpoint URL"). The WSDL URL should now be a full versioned service URL (for example, `https://wd2-impl-services1.workday.com/ccx/service/amn1/Human_Resources/v28.2`), not a bare `/ccx` address. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Workday integration. # Workvivo Source: https://docs.serval.com/sections/integrations/workvivo Connect Workvivo, Zoom's employee experience platform, to Serval so workflows can read from and post to your intranet through the Workvivo API. ## About Workvivo Workvivo is Zoom's employee experience platform - the home for your company intranet, social feed, and internal communications. The Serval Workvivo integration connects with an API token: a Workvivo admin pastes a bearer token, your Organisation Id, and your API base URL into Serval. Serval stores the token securely on its servers and attaches your credentials automatically whenever a workflow talks to Workvivo - the token is never exposed to workflow builders or returned to the browser after you save it. **Authentication:** API token (a bearer token from a Workvivo API app, plus your Organisation Id and API base URL). **Data sync:** On demand only. Workflows call Workvivo when they run - there is no background data sync, no entity ingestion, and no inbound webhooks. Five scheduled health checks confirm the connection stays valid. ## What the Workvivo integration enables | Capability | Description | | - | - | | Workvivo API request (workflow action) | Workflows get typed access to the full Workvivo v1 API - 210 endpoints covering articles, updates, kudos, events, users, chat bots and channels, spaces, pages, teams, notifications, badges, documents, goals, livestreams, and more. | | Connection health checks | Five scheduled checks continuously verify that your token, Organisation Id, base URL, and permission scopes still work. | | AI workflow context | Each connected Workvivo instance is visible to workflows and Serval AI, so even multi-instance setups can target the right Workvivo tenant. | Anything defined in the [Workvivo API](https://developer.workvivo.com/) can be accessed through Serval. ## Get your credentials You need three values, all shown on the same screen in Workvivo's developer admin: a bearer token from a Workvivo API app, your Organisation Id, and your API Base URL. Creating the app requires the Workvivo **Developer** role. Workvivo's official walkthrough is here: [API Authentication - Bearer Token](https://support.workvivo.com/hc/en-gb/articles/24560593493661-API-Authentication-Bearer-Token) (see also the [Workvivo API Overview](https://support.workvivo.com/hc/en-gb/articles/33276763921309-Workvivo-API-Overview) and the full [APIs help section](https://support.workvivo.com/hc/en-gb/sections/4917959499165-APIs)). Workvivo warns that Developer-role users can create API apps with up to Admin-level permissions, including actions the normal UI restricts. Grant the role sparingly, and give the Serval app only the scopes it needs. Have a Workvivo admin grant your user the Developer role. This unlocks the "API Keys and JWT settings" option in the Workvivo admin panel. In your Workvivo admin panel, open API Keys and JWT settings (Admin > Developers > Apps). Workvivo tenants live on their own domains, so navigate there from inside your own Workvivo instance. Your numeric Organisation Id is shown on this screen. This is the "Workvivo-Id (Organisation Id)" value Serval asks for. Create a new app, name it, and select only the permissions the integration needs. Include the chats.bots.read scope if you want all five Serval health checks to pass. Scopes can be changed later. Click Manage Keys on the app, then Add new Key, and copy the bearer token that populates. Note the Base URL shown when creating the Access Token (Apps > App Settings). Use the exact API host for your tenant, such as api.workvivo.com, api.eu2.workvivo.com, or api.workvivo.us. Enter it in Serval without https\://, a path, or a trailing slash. Keep the domain ending shown by Workvivo; don't replace .us with .com. The token is only shown when the key is created, and the Organisation Id and Base URL appear on the same screens - capture all three values at once. ## Connect in Serval In Serval, go to your integrations page and choose Workvivo. All three fields are required (marked with an asterisk). Type the bare host exactly as Workvivo showed it, for example api.workvivo.com or api.workvivo.us. Don't include https\://, a path, or a trailing slash. The form rejects invalid hosts with "Must be a valid Workvivo API host (e.g. api.workvivo.com, api.eu2.workvivo.com, or api.workvivo.us). Do not include https\:// or a path." Leaving it blank shows "This field is required". Paste your numeric Organisation Id, for example 12345. It is sent with every request Serval makes to Workvivo. Leaving it blank shows "This field is required". Paste the bearer token from Manage Keys. This is a password field and is stored as a secret. On first setup the token is required - if you submit without it, Serval rejects the form with an error that includes "API Token is required". Click Submit. The connection appears as "Workvivo (\[Organisation Id])", and Serval's health checks then run automatically. When editing an existing connection, the API Base URL and Workvivo-Id come pre-filled with their saved values, and the API Token field appears empty. Leaving the token blank keeps the saved token - so you can change the other fields, or rotate just the token, without re-entering everything. ## Verifying the connection Serval runs five scheduled health checks against your Workvivo tenant: * **Validate Workvivo API Connection** - confirms Workvivo accepts your token, Organisation Id, and base URL. * Success: "Successfully authenticated with the Workvivo API." * Failure: "Unable to connect to the Workvivo API. Verify the API token, Workvivo-Id header, and base URL are correct." * **Check Workvivo Users Read Access** - confirms the token can read your user directory. * Success: "Successfully listed users (\[number] returned)" * Failure: "Failed to list Workvivo users. The token may be missing user-read permissions." * **Check Workvivo Teams Read Access** - confirms the token can read your teams. * Success: "Successfully listed teams (\[number] returned)" * Failure: "Failed to list Workvivo teams. The token may be missing teams-read permissions." * **Check Workvivo Spaces Read Access** - confirms the token can read your spaces. * Success: "Successfully listed spaces (\[number] returned)" * Failure: "Failed to list Workvivo spaces. The token may be missing spaces-read permissions." * **Check Workvivo Chat Bots Read Access** - confirms the token has the chats.bots.read scope, which Serval validates ahead of a planned chat capability. * Success: "Successfully listed chat bots (\[number] returned)" * Failure: "Failed to list Workvivo chat bots. The token is likely missing the chats.bots.read scope; chat-source flows will not work until this is granted." If your tenant simply has no items of a given type yet, the check still passes with a "Successfully reached the ... endpoint" message instead of a count. The most common partial failure: every check is green except "Check Workvivo Chat Bots Read Access". That means your API app is missing the chats.bots.read scope. Your workflows and the other checks are unaffected - grant the scope in Workvivo (or accept the single failing check). ## Gotchas and troubleshooting The form accepts Workvivo API hosts ending in workvivo.com or workvivo.us, including regional hosts such as api-eu.workvivo.com and api.eu2.workvivo.com. Don't include https\://, a path, or a trailing slash. Lookalike domains are rejected. The Organisation Id (Workvivo-Id), the bearer token, and the Base URL are all surfaced in Workvivo's developer admin during app and token creation. Capture all three at once - the token is only shown when the key is created. The "Check Workvivo Chat Bots Read Access" check requires the chats.bots.read scope on your token. If your app lacks that scope, this single check fails while API actions and the other four checks keep working. Grant the scope, or accept the failing check - it exists to validate a future chat capability early. On the edit form the API Token field appears empty even though a token is saved - Serval never sends the stored token back to the browser. Leaving it blank preserves the stored token, so to rotate it, paste the new value and submit. The base URL and Organisation Id come pre-filled and cannot be saved blank (clearing one shows "This field is required"). Note that changing the Workvivo-Id or base URL changes how the connection is identified and displayed in Serval. Workvivo's own documentation warns that the Developer role lets a user create API apps that can be granted up to Admin permissions, including actions the UI normally restricts. Grant the role only to trusted admins, and give the Serval app the minimum scopes it needs. Workvivo is API-actions-only today: no webhooks, no background sync, and it cannot act as a Serval chat source yet. For workflow builders: list results page through with skip and take settings, and list-style filters separate multiple values with the pipe character (for example in\_teams=1|2|3). *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Workvivo integration. # xMatters Source: https://docs.serval.com/sections/integrations/xmatters Connect xMatters to find on-call responders, page groups, and manage alert activity. The xMatters integration provides group search, on-call lookup, alert inspection, response lookup, paging, comments, and alert lifecycle actions. ## Connect xMatters 1. Choose an xMatters integration user with access to the groups and alerts you want Serval to use. The connection inherits this user's permissions. 2. Open the user's profile, then select **More Actions → Manage API Keys → Create API Key Credential**. Create a credential and save its API key and one-time secret. See [xMatters API key administration](https://help.xmatters.com/ondemand/user/apikeys.htm). 3. In Serval's app catalog, select **xMatters** and connect an instance. 4. Enter an instance name, your tenant hostname (for example, `company.xmatters.com`), the API key, and its secret. The `x-api-key-` prefix is optional. Use the hostname only; do not paste a trigger URL here. 5. Run the connection health checks. They read groups, alerts, and one visible on-call group's schedule without sending notifications. If no on-call group is visible, the schedule check reports that it was not exercised. The API key and secret are stored as integration credentials. You can rotate them in the connection form. To change the tenant hostname, create a new connection. Revoking the key or deleting its xMatters user prevents the connection from working. ## Configure paging An xMatters administrator must set up the [Trigger Alerts by Webhook template](https://help.xmatters.com/integrations/other/triggeralertsbywebhook.htm) and enable its flow. Select **API Key Authentication** for the HTTP trigger. The trigger's **Basic Authentication** option is for a user password and does not accept these API-key credentials. Copy the trigger UUID from the URL path: ```text theme={null} https://company.xmatters.com/api/integration/1/functions/TRIGGER_UUID/triggers ``` Use that UUID as the **Trigger ID** input to **Page an xMatters Group**. Find the recipient using **Find xMatters Groups**, then supply its explicit group UUID, summary, and message. Serval supplies the resolved group name in both the recipients query parameter and the template payload, replacing the default recipient from the copied URL. Group names containing commas are not supported by this workflow; choose an unambiguous group name in xMatters. The workflow maps its message to the template's `description` field and sends `MEDIUM` priority. Custom flows may need a custom Serval workflow. The xMatters flow controls escalation and delivery. ## Install workflows The **Alerting and On-Call** bundle includes: | Workflow | Behavior | Default approval | | - | - | - | | Find xMatters Groups | Search groups and return their UUIDs | None | | Get xMatters On-Call Responders | Read shifts and members for one group | None | | Search xMatters Alerts | Filter alerts or correlate a trigger request | None | | Get xMatters Alert Details | Read properties, status, and comments | None | | Get xMatters Alert Responses | Read current response audit entries | None | | Page an xMatters Group | Submit a paging flow for an explicit group | Installer | | Add an xMatters Alert Comment | Add a comment without acknowledging | Installer | | Change xMatters Alert Status | Resume, suspend, or terminate notifications | Installer | ## Interpret results A paging result marked **accepted** means xMatters accepted the flow request. It does not confirm alert creation or delivery. Use **Search xMatters Alerts** with the returned `requestId` to find resulting alerts. The search can initially be empty or return more than one alert. Inspect response entries separately. List workflows return one bounded page with `hasMore` and `nextOffset`. Pass the next offset to continue. On-call results also indicate whether nested member lists are incomplete. An empty result only describes data visible to the API user. Lifecycle actions accept `ACTIVE` (resume), `SUSPENDED` (pause), and `TERMINATED` (stop permanently). Termination cannot be undone. None is an acknowledgment. The API calls alerts **events**, and workflows use their UUIDs rather than their numeric display IDs. ## Troubleshooting * **401 or 403:** check the key, secret, user's status and permissions, and the trigger's authentication setting. REST access and flow-trigger access are separate checks. * **429 or server errors during reads:** Serval makes up to three attempts using bounded backoff. If the read still fails, try again later. * **Paging timeout or interruption:** a page might already have been sent. Inspect the xMatters Activity log before retrying. Paging has no exactly-once guarantee. * **No alert found for a request ID:** allow time for the flow to execute and check its Activity log. Do not resubmit a page solely because this search is empty. This integration does not automatically create xMatters flows, edit schedules, provision users, or synchronize Serval tickets through callbacks. # Zendesk Source: https://docs.serval.com/sections/integrations/zendesk Connect Zendesk to Serval for full Support API access in workflows, two-way help desk ticket sync, and Zendesk Guide knowledge sync. ## About Zendesk Zendesk is a customer-service platform for support ticketing and self-service knowledge. Serval connects to a single Zendesk instance and, through one connection, covers both Zendesk Support (tickets, comments, users, organizations, custom statuses) and Zendesk Guide (Help Center categories, sections, and articles). Zendesk is registered in Serval as both a ticket source and a knowledge source. **Authentication:** OAuth 2.0 client credentials - you create a **confidential** OAuth client in Zendesk Admin Center and give Serval its Client ID and Client Secret. Serval requests tokens with the `read write` scopes; within those, everything Serval can do is bounded by the role of the Zendesk user who created the OAuth client. Zendesk is [retiring API tokens](https://support.zendesk.com/hc/en-us/articles/10851263566234) as an authentication method: new Zendesk accounts cannot create tokens after **July 28, 2026**, no one can create new tokens after **October 27, 2026**, and **all API tokens stop working on April 30, 2027**. New Serval connections therefore use OAuth. If you connected Zendesk with an email + API token, switch the connection to OAuth before April 30, 2027 - see [Migrating an API-token connection to OAuth](#migrating-an-api-token-connection-to-oauth). **Data sync:** Workflow API calls run on demand. Ticket sync is a two-way background sync - Serval checks connected channels for new and updated tickets every 30 seconds and pushes Serval-side changes (new tickets, comments, status, priority, and field updates, including custom statuses) back to Zendesk. Zendesk Guide knowledge sync discovers all Help Center categories, sections, and articles, then ingests article content per item - newly discovered items start out excluded from sync, so you opt in exactly the content you want indexed. Group sync is off until an admin enables resource sync on the connection; once on, Serval refreshes Zendesk groups and their membership every two hours. ## What the Zendesk integration enables | Capability | Description | | - | - | | Full Zendesk Support API access | A typed API action covering 424 Zendesk Support endpoints, generated from [Zendesk's official OpenAPI specification](https://developer.zendesk.com/zendesk/oas.yaml) - tickets, users, organizations, ticket fields, custom statuses, automations, custom objects, brands, audit logs, and more. Rate-limited requests are retried automatically. | | Two-way ticket sync | Use Zendesk as a Serval help desk channel. Serval pulls tickets and comments in the background (with an incremental sync for channels configured to capture historical and new tickets, and a bulk backfill if a channel falls more than 48 hours behind) and writes Serval-side ticket creates, updates, and comments back to Zendesk. Priorities map between systems (Zendesk urgent/high/normal/low ↔ Serval urgent/high/medium/low; Serval "none" is written to Zendesk as low). | | Zendesk Guide knowledge sync | Syncs Help Center categories, sections, and articles into Serval's knowledge base, preserving the category → section → article hierarchy. Each item has an include-in-sync setting, and newly discovered items start out excluded, so you scope exactly which Guide content Serval indexes. | | Group sync | Turn on resource sync for the connection and Serval keeps your Zendesk groups, and their agent membership, current as Serval groups on a scheduled background sync. Those groups can then be used in access-profile conditions. Membership is managed in Zendesk - Serval reads it and never writes it back. | | Guide permission sync | With permission sync enabled on the knowledge source, Serval mirrors each article's user-segment visibility, and with enforcement turned on it only answers from articles the requester can view in your Help Center. Segment membership (user type, tags, organizations, groups) is checked against Zendesk at question time, so Zendesk itself evaluates the rules. | | Shipped workflow: List Zendesk Tickets | A pre-installed workflow (runs without approval by default) that lists all tickets with cursor pagination and optional filters: an external ID, and a support-type scope of all, agent, or ai\_agent (defaults to agent). | | Help Center article link recognition | Paste a Zendesk Help Center article link in Serval and it resolves to the matching synced article automatically. | Anything defined in the [Zendesk API](https://developer.zendesk.com/api-reference/) can be accessed through Serval. ## Get your credentials You need an OAuth client created in your Zendesk instance. You must be a Zendesk administrator to create one. See [Zendesk's OAuth guide](https://support.zendesk.com/hc/en-us/articles/4408845965210) for full details. Zendesk attributes every API action performed with a client-credentials token to **the user who created the OAuth client** - ticket comments, audit log entries, everything. Create the client while signed in as a dedicated service account (e.g. "Serval Integration") rather than a personal admin account, so attribution stays stable when people leave and actions are clearly labeled in your audit trail. Serval's access mirrors that user's Zendesk role, so it should be an admin or an agent whose permissions cover reading and updating tickets and reading the Help Center. In Zendesk Admin Center, click **Apps and integrations** in the sidebar, then select **APIs → OAuth clients** (labeled "Zendesk API OAuth clients" in some accounts). Click **Add OAuth client** and give it a recognizable name, e.g. "Serval Integration". Set **Client kind** to **Confidential** (not Public) - this is required. Leave **Redirect URLs** blank: client credentials is a server-to-server flow with no browser step, so no redirect URL is needed. Click **Save** to generate the client. Copy the **Unique Identifier** (the Client ID) and the **Secret** immediately - Zendesk shows the full secret only once. **Client kind must be Confidential.** Serval authenticates with the OAuth 2.0 client-credentials grant, and Zendesk permits that grant only for confidential clients. A **Public** client saves and its Client ID and Secret are accepted, but every token request is then rejected, so the connection fails its health checks with `unauthorized_client` ("The authenticated client is not authorized to use the access grant type provided"). If you see that, recreate the client as **Confidential**. This is the most common Zendesk setup mistake. Zendesk displays the client secret only once, at creation time. Copy it before closing the window - Serval never displays it again either (it is shown obfuscated, with only the last 4 characters visible). ## Connect in Serval Open the Zendesk integration in Serval and fill in the connect form. A friendly name for this Zendesk integration instance (e.g., "Production Zendesk"); if empty, we will use the domain. When set, the connection displays as "Name (domain)". Your Zendesk subdomain or domain - `company` and `company.zendesk.com` both work, and a pasted Zendesk URL is normalized automatically. Host-mapped or vanity domains will not authenticate; the connection always targets the canonical `.zendesk.com` address. The Unique Identifier of the OAuth client you created in Zendesk Admin Center. This is a password field. The Secret of that OAuth client. This is a password field. Save the connection. If saving fails, the error begins with "Failed to install integration" (first-time connect) or "Failed to update integration" (editing an existing connection), followed by details when available. When you edit an existing connection, the form opens pre-filled with your saved settings; secrets appear masked with only the last 4 characters visible. Masked values are ignored when you save, so stored secrets are preserved unless you paste in a new one - and if you clear the Domain or Instance Name, the stored value is kept too. ## Migrating an API-token connection to OAuth Connections created before OAuth support use an email address + API token. Those keep working for now, but Zendesk disables all API tokens on **April 30, 2027**, so every token-based connection must be switched to OAuth before then. The migration is being rolled out to teams with existing Zendesk connections - if you don't see the authentication-method selector yet, contact [support@serval.com](mailto:support@serval.com). Follow [Get your credentials](#get-your-credentials) above - remember to create the client as a dedicated service account. Edit your existing Zendesk connection in Serval (don't create a new one - your ticket sync, knowledge sync, and workflows all stay attached to the existing connection). Set **Authentication method** to **OAuth 2.0**, paste the Client ID and Client Secret, and save. Re-run the health checks. All four should pass exactly as before. Your API token stays stored (until Zendesk's final cutoff): switching **Authentication method** back to **API token (legacy)** and saving reverts the connection without re-entering the token. Fix the OAuth client, then switch forward again. After switching to OAuth, ticket comments and audit entries in Zendesk are attributed to the OAuth client's creator instead of the email/token user - another reason to create the client from a dedicated service account. ## Verifying the connection Serval runs four health checks against your Zendesk connection. **Test Zendesk Connection** - confirms the domain and credentials work by fetching the connected user's profile. * Success: "Successfully authenticated with Zendesk as \[name]" * Failure: "Unable to authenticate with Zendesk. Please verify your credentials (OAuth client ID and secret, or email and API token) are correct." **List Zendesk Tickets** - confirms the account can list tickets (a small sample of ticket fields is recorded for diagnostics). * Success: "Successfully listed tickets from Zendesk (sample size: \[number])" * Failure: "Unable to list tickets from Zendesk. Please verify your API credentials have permission to read tickets. This is required for the integration to function." **List Zendesk Organizations** - confirms the account can list organizations. * Success: "Successfully listed organizations from Zendesk (sample size: \[number])" * Failure: "Unable to list organizations from Zendesk. Please verify your API credentials have permission to read organizations." **List Zendesk Knowledge Articles** - confirms the account can read Zendesk Guide knowledge base articles. * Success: "Successfully listed knowledge articles from Zendesk Guide (sample size: \[number])" * Failure: "Unable to list knowledge articles from Zendesk Guide. Please verify your API credentials have permission to read the knowledge base, or that Zendesk Guide is enabled for your account." If the first three checks pass but **List Zendesk Knowledge Articles** fails, the most likely cause is that Zendesk Guide is not enabled for your account, or the connecting user cannot read the Help Center. Ticket features continue to work - only knowledge sync is affected. ## Gotchas and troubleshooting If the connection saves but the health checks cannot authenticate, and the underlying error is `unauthorized_client` ("The authenticated client is not authorized to use the access grant type provided"), the OAuth client was created with **Client kind: Public**. Zendesk allows the client-credentials grant only for **Confidential** clients, so a public client's Client ID and Secret are accepted but every token request is rejected. Recreate the client as **Confidential** in Zendesk Admin Center, then re-save the connection with the new Client ID and Secret. This is different from an `invalid_client` error, which means the Client ID, Secret, or Domain is wrong rather than the client kind. Zendesk disables all API tokens on April 30, 2027 (and blocks creating new ones from October 27, 2026). Token-based Serval connections stop working at that point. Switch your existing connection to OAuth using the migration steps above - editing the existing connection keeps your ticket sync, knowledge sync, and workflows intact, while creating a new connection would not. With client-credentials OAuth, Zendesk attributes every API action to the user who created the OAuth client. Create the client from a dedicated service account so ticket comments and audit entries are clearly labeled and survive personnel changes. Serval's permissions mirror that account's Zendesk role. The connect-form fields have minimal format checks (only the Domain is validated), so the form can save with missing or malformed credentials. If something is wrong, the health checks will tell you - start with **Test Zendesk Connection**, which validates the domain and credentials together. Serval only sends credentials to `*.zendesk.com` addresses, and all traffic is routed to the subdomain derived from your configured Domain. Host-mapped or vanity Help Center domains will not authenticate - enter your canonical subdomain (`company` or `company.zendesk.com`). Serval requests the `read write` OAuth scopes; within those, everything it can read or write is bounded by the Zendesk role of the OAuth client's creator (or, for legacy connections, the agent or admin whose email and token you supplied). Writing tickets back to Zendesk (creates, updates, custom statuses, ticket fields) and syncing Guide knowledge each require the corresponding Zendesk permissions on that account. Knowledge sync and the knowledge-articles health check both read the Help Center. If Guide is not enabled for your account (or the connecting user cannot read it), the ticket checks pass while the knowledge check fails - its failure message calls this out explicitly. When Serval first discovers your Help Center content, every category, section, and article is created with sync turned off. Nothing is indexed until you explicitly include the items you want - so an empty knowledge base right after connecting is expected, not a failure. Permission enforcement checks a requester's segment membership through Zendesk's user-segments API. When the connecting account is a non-admin agent, Zendesk only reports the segments that agent shares with the requester, so restricted articles can be withheld from users who are actually entitled to them (never the reverse). Connect with an admin account for full-fidelity enforcement. Zendesk's account-level "Require sign in" Help Center setting is not exposed through the articles API, so articles without a user segment are treated as unrestricted in Serval even when your whole Help Center requires sign-in. Restrict sensitive articles with user segments if you need Serval to enforce their visibility. The edit form opens pre-filled, and clearing a field does not wipe anything: a cleared Domain keeps the existing domain, a cleared Instance Name keeps the existing display name, and masked secrets are ignored on save so stored credentials are preserved. To rotate a secret, paste the new value over the masked one and save. On a legacy connection, changing the Email Address alone also works - Serval recombines the new email with the stored API token. Copy the OAuth client secret (or, for legacy connections, the API token) when you create it in Zendesk Admin Center. Serval never displays it again either - reads show it obfuscated, with only the last 4 characters visible. If a secret is lost, generate a new one in Zendesk and paste it into the connection form in Serval. When Zendesk rate-limits a request, Serval retries automatically - waiting the time Zendesk specifies, or backing off progressively when no wait time is given. Very high-volume workflows can still exhaust your instance's limit; workflows that fetch large amounts of data should use [cursor pagination](https://developer.zendesk.com/api-reference/introduction/pagination/) to minimize the number of calls. The typed API action covers the 424 Zendesk Support endpoints from Zendesk's official specification; Zendesk Guide (Help Center) endpoints are not part of that typed list. Guide content is still fully reachable - the built-in health check and the knowledge sync use it directly, and custom workflow calls to Guide work through the same authenticated connection, just without typed assistance. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Zendesk integration. # Zoho CRM Source: https://docs.serval.com/sections/integrations/zoho-crm Connect Zoho CRM to Serval so workflows can manage CRM users, roles, profiles, groups, and territories, and read or write CRM records. ## About Zoho CRM Zoho CRM is a customer relationship management platform. Serval connects to it through a Serval-managed Zoho OAuth application, so there is nothing to register in the Zoho API Console. You choose which permissions to grant when you connect, and your Zoho data center is detected automatically. **Authentication:** Zoho OAuth 2.0 with a Serval-managed application. You approve access on Zoho's consent screen; there are no API keys to paste. **Data sync:** On demand only. Workflows call Zoho CRM at run time through a single API request action. There is no background sync. ## What the Zoho CRM integration enables | Capability | Description | | - | - | | API request action | A single typed action, **Zoho CRM API request**, covering 74 operations from the Zoho CRM v8 API, with automatic authentication and token refresh. | | User management | List users, invite new users, change a user's role or profile, deactivate users, and delete users. | | Access structure | Read and manage roles, profiles, user groups, and territories, including which users belong to each. | | Organization details | Read organization details such as the organization ID, currency, and license counts. | | CRM records | Read, create, update, upsert, clone, and delete records in any module (leads, contacts, accounts, deals, and custom modules), and read or change module and field metadata. | Anything in the typed operations can be called from a workflow. For endpoints outside them, see the [Zoho CRM v8 API reference](https://www.zoho.com/crm/developer/docs/api/v8/). ## Before you connect Sign in with the Zoho account whose CRM organization you want to connect. To use the user, role, profile, group, or territory management permissions, the account must have the Administrator profile in Zoho CRM. Read access to users and organization details is always included. Everything else is optional; see the permission presets below. Zoho CRM sandbox and developer editions aren't supported. Zoho issues separate tokens for each environment, and Serval connects to production organizations only. ## Connect in Serval In Serval, go to **Integrations > All integrations > Zoho CRM**. A permissions modal opens. Check any presets your workflows need. Expand a preset to see the exact Zoho scopes it requests. | Preset | Zoho scopes requested | | - | - | | View roles, profiles, groups, and territories | `ZohoCRM.settings.roles.READ`, `ZohoCRM.settings.profiles.READ`, `ZohoCRM.settings.user_groups.READ`, `ZohoCRM.settings.territories.READ` | | Manage users | `ZohoCRM.users.CREATE`, `ZohoCRM.users.UPDATE`, `ZohoCRM.users.DELETE`, plus read access to roles and profiles | | Manage user groups and territories | `READ`, `CREATE`, `UPDATE`, and `DELETE` on `ZohoCRM.settings.user_groups` and `ZohoCRM.settings.territories` | | Manage roles and profiles | `READ`, `CREATE`, `UPDATE`, and `DELETE` on `ZohoCRM.settings.roles` and `ZohoCRM.settings.profiles` | | Read CRM records | `ZohoCRM.modules.READ`, `ZohoCRM.settings.modules.READ`, `ZohoCRM.settings.fields.READ` | | Create and update CRM records | `ZohoCRM.modules.CREATE`, `ZohoCRM.modules.UPDATE`, plus the read scopes above | | Manage modules and fields | `CREATE` and `UPDATE` on `ZohoCRM.settings.modules`, `CREATE`, `UPDATE`, and `DELETE` on `ZohoCRM.settings.fields`, plus read access to both | | Delete CRM records | `ZohoCRM.modules.DELETE`, plus `ZohoCRM.modules.READ` | Serval never requests Zoho's wildcard `.ALL` scopes. Authorization opens in a popup window or a full-page redirect. Sign in and approve the requested permissions. Zoho shows the consent screen on every connect and reconnect; this is expected. `ZohoCRM.users.READ` and `ZohoCRM.org.READ` are always requested, so a connection with no presets selected can still list users and read organization details. Serval detects your Zoho data center (US, EU, IN, AU, JP, CN, CA, SA, UK, UAE, or Singapore) from the authorization response. All API calls and token refreshes then use that data center's servers. ## Changing permissions Permissions are fixed when you connect. To add or remove permissions, reconnect the integration. The modal opens with the presets you already granted checked. Any granted permission that no checked preset covers is listed under **Keep current permissions** and kept by default; clear that box to drop them. Change the selection and approve on Zoho again. ## Verifying the connection After connecting, Serval runs three health checks. All three use only the always-included scopes, so they pass regardless of which presets you chose. **Test Zoho CRM Connection** reads your organization details. * Success: "Successfully authenticated with Zoho CRM" * Failure (invalid token or missing scope): "Unable to authenticate with Zoho CRM. The OAuth token is invalid, expired, or missing a required scope. Reconnect the integration." * Failure (other): "Unable to reach Zoho CRM. Check that the connected Zoho account has access to a CRM organization." **List Zoho CRM Users** lists a sample of active users. * Success: "Successfully listed active Zoho CRM users (sample size: \[number])" * Failure: "Unable to list Zoho CRM users. Reconnect the integration so the ZohoCRM.users.READ scope is granted." **Read Connected Zoho CRM Account** reads the Zoho user the connection authenticates as. * Success: "Connected as a Zoho CRM user with the \[profile] profile" * Failure: "Unable to read the connected Zoho CRM user. Reconnect the integration." The user, group, territory, role, and profile management presets only work when the connected account has the Administrator profile. If the third check reports a different profile, reconnect with an administrator account. ## Gotchas and troubleshooting The connection wasn't granted the scope that operation needs. Reconnect and check the preset that covers it. For example, changing a user's role needs **Manage users**. Zoho runs the organization's workflow rules, approvals, and blueprints when records are created or updated through the API. To skip them, pass an empty `trigger` array in the request body (`"trigger": []`). Zoho only allows administrators to add, change, or delete users. Reconnect while signed in to a Zoho account with the Administrator profile. Token refresh is automatic. A persistent authentication failure usually means the grant was revoked in Zoho. Reconnect the integration to create a new grant. # Zones Source: https://docs.serval.com/sections/integrations/zones Connect Serval to Zones to create purchase orders, track order status, and read the standard and non-standard product catalogs on demand. ## About Zones Zones is an IT solutions and hardware reseller. Serval connects to the Zones API to place and track orders and to read product catalogs, calling Zones' REST API on your behalf whenever a Serval workflow runs. **Authentication:** A Zones API **subscription key** (sent as the `Ocp-Apim-Subscription-Key` header) plus **OAuth 2.0 client credentials** (Client ID, Client Secret, and a Scope). Serval exchanges the client credentials for a short-lived bearer token at Zones' token endpoint and sends both the bearer token and the subscription key on every request. **Environment:** Choose **Production** (`api.zones.com`) or **Sandbox** (`apitest.zones.com`) when you connect. Match this to the environment your credentials belong to — Zones' gateway rejects a production subscription key sent to the sandbox host, and vice versa. **Data sync:** On-demand only - there is no background sync or scheduled ingestion. Serval reads from and writes to Zones at the moment a Serval workflow runs. The Zones **Advance Shipment Notification (ASN)** service is a separate, event-driven product: Zones *pushes* shipment updates to a URL you register, rather than exposing endpoints Serval calls. It is not part of this integration, which covers the Orders and Product Catalog REST APIs. ## What the Zones integration enables | Capability | Description | | - | - | | Create purchase orders | `POST /orders/v1/purchase-order` submits a new order to Zones, returning the created order reference. | | Track order status | `GET /orders/v1/purchase-order/{zonesOrderNumber}` retrieves full details and tracking information for an existing order. | | Read the product catalog | `GET /catalog/v1/standards` and `GET /catalog/v1/non-standards` return the standard and non-standard product catalogs. | | Call any Zones API endpoint | A generic, typed API request action exposes every endpoint above with request/response types generated from the Zones OpenAPI specification. | ## Get your credentials Serval needs two things from the [Zones developer portal](https://developer.zones.com): a **subscription key** and an **OAuth client** (Client ID, Client Secret, and Scope). Go to [developer.zones.com](https://developer.zones.com) and sign in with your Zones developer account. Open your **Subscriptions** (or **Profile**) page and copy the subscription key for the products you need (Orders API and Product Catalog). This value is sent as the `Ocp-Apim-Subscription-Key` header on every request. Treat the subscription key like a password. If it's ever exposed, regenerate it from the portal and update the Serval connection. On your **Profile** page, open the **Environment Secrets** section. Copy the **Client ID**, **Client Secret**, and the **Scope** (the app name used as the token scope). The Scope is the application name shown alongside the client credentials - not a permission string. Copy it exactly as shown. ## Connect in Serval All fields are required. The form flags any required field left blank, and an incomplete configuration that reaches Serval's backend is rejected with a message beginning "Invalid Zones configuration" (for example, "subscription key is required" or "client ID is required"). Select **Production** (`api.zones.com`) or **Sandbox** (`apitest.zones.com`). This determines which Zones host Serval sends orders, catalog reads, and token requests to. Defaults to Production. Your Zones API subscription key from the developer portal's Subscriptions page. Stored encrypted. When editing the connection later, it appears obfuscated - leave it unchanged to keep the stored value. The OAuth client ID from the Environment Secrets section of your Zones profile. The OAuth client secret from the same section. Stored encrypted; obfuscated on the edit form - leave it unchanged to keep the stored value. The app name used as the token scope, from the Environment Secrets section. Connections made before the Environment selector existed have no environment stored and must be reconnected to choose Production or Sandbox. ## Verifying the connection After saving, Serval runs these health checks: * **Test Zones Connection** - performs the full client-credentials token exchange, then fetches the standard catalog to confirm both the subscription key and token are valid. On success: "Successfully authenticated with Zones". On failure: "Unable to connect to Zones. Please verify your Subscription Key, Client ID, Client Secret, and Scope are valid." * **List Zones Standard Catalog** - confirms the Product Catalog API is reachable by fetching the standard catalog. * **List Zones Non-Standard Catalog** - confirms the Product Catalog API is reachable by fetching the non-standard catalog. ## Gotchas and troubleshooting Zones requires two credentials on each Orders/Catalog call: the `Ocp-Apim-Subscription-Key` header and an `Authorization: Bearer` token. Serval handles both automatically - it exchanges your Client ID, Client Secret, and Scope for a bearer token and attaches the subscription key. A `401` usually means the bearer token or client credentials are wrong; a `403` typically means the subscription key lacks access to the product being called. The Scope field is the application name from the portal's Environment Secrets, sent verbatim in the token request. If it doesn't match what the portal shows, the token exchange fails and requests are rejected. Update it in Serval whenever it changes in the portal. Zones access tokens expire about an hour after they're issued. Serval requests a fresh token as needed, so no action is required - but a token endpoint outage surfaces as an authentication failure even when your credentials are correct. This integration targets `apitest.zones.com`. Make sure the subscription key and client credentials you enter belong to the same environment. For teams building custom automations through the generic API request action, paths already include the product prefix - for example `/orders/v1/purchase-order` and `/catalog/v1/standards`. Do not add `https://` or the host; Serval routes requests to Zones automatically. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Zones integration. # Zoom Source: https://docs.serval.com/sections/integrations/zoom Zoom is a video communications platform for meetings, phone, and conference rooms - Serval connects to it to pull meeting reports, attendance, and Q&A data, and to manage meeting and phone delegates through workflows. ## About Zoom Zoom is a video communications platform covering meetings, phone, and conference rooms. Serval connects to your Zoom account through a Server-to-Server OAuth app that you create in the Zoom App Marketplace, then calls the Zoom REST API on your account's behalf. The integration spans three Zoom product areas - users, meetings, and rooms - so workflows can read meeting history and reports, manage user settings, and work with Zoom Rooms. **Authentication:** Server-to-Server OAuth (OAuth 2.0 client credentials). You provide the Account ID, Client ID, and Client Secret from a Server-to-Server OAuth app in the Zoom App Marketplace - no browser sign-in is involved. **Data sync:** On-demand only. Serval runs no background sync, polling, or webhook ingestion for Zoom - data is read or written at the moment a workflow runs. ## What the Zoom integration enables | Capability | Description | | - | - | | Get Attendance Report for a Meeting | Detailed attendance report for a Zoom meeting - meeting details, participant count, duration, and each participant's join/leave times and email. Shipped workflow; no approval required. | | Get Q\&A of a Meeting | Fetches the question-and-answer data from a past meeting: every question asked by attendees and the corresponding answers. Shipped workflow; no approval required. | | List Meeting Participants | The participant list from a past meeting, including names, emails, join times, and leave times. Shipped workflow; no approval required. | | List Zoom Meetings | Historical meetings for a user within a date range - topics, times, durations, and IDs. Shipped workflow; no approval required. | | Update Zoom Meeting and Phone Delegate for User | Adds or removes a person as both a Zoom Meetings scheduling assistant and a Zoom Phone call delegate for a target user. Requires the user write admin, phone read admin, and phone write shared setting admin scopes on your Zoom app. Shipped workflow; installer approval by default. | | Typed Zoom API access | Custom workflows can call nearly 200 Zoom endpoints through three product submodules - `zoom.users` (users, groups, contact groups, assistants, settings, status), `zoom.meeting` (meetings, webinars, registrants, polls, recordings, past meetings, and reports), and `zoom.rooms` (rooms, devices, locations, tags, calendar services, workspaces). | Anything in the integration's typed users, meetings, and rooms surface of the [Zoom API](https://developers.zoom.us/docs/api/) can be accessed through Serval. ## Get your credentials Serval authenticates with a Server-to-Server OAuth app that lives in your Zoom account. You create the app once, enable the scopes your workflows need, and copy three values from its App Credentials page. Zoom's official guide: [Create a Server-to-Server OAuth app](https://developers.zoom.us/docs/internal-apps/create/). Log in to your Zoom account and navigate to the [Zoom App Marketplace](https://marketplace.zoom.us/user/build). Click **Develop**, then **Build App**. Choose the **Server to Server OAuth app** type and give it a name. Continue through the setup process, selecting scopes for any APIs you want to access via Serval. Report-based workflows need report scopes; the delegate workflow needs the user write admin, phone read admin, and phone write shared setting admin scopes. Activate the app so it can issue tokens. Open the app's **App Credentials** page and copy the **Account ID**, **Client ID**, and **Client Secret**. Scopes are chosen entirely on the Zoom side. Serval never requests or narrows scopes during connection - the connection carries exactly the scopes enabled on your Zoom app, and scope changes made in Zoom take effect the next time Serval mints a token. To modify scopes after creating the app, return to the [Zoom App Marketplace](https://marketplace.zoom.us/user/build), click your app, open the **Scopes** tab, and click **Add Scopes**. ## Connect in Serval The Zoom connect form has four fields. None of them display inline validation messages, but all four are needed for a working connection - Serval sends the Account ID with every token request and uses the Client ID and Client Secret to mint access tokens. Paste the **Account ID** from your app's App Credentials page. Serval stores it with the connection and sends it on every token request, so tokens are always scoped to this account. Enter an **Account Name** - a friendly label Serval displays for this connection. Paste the **Client ID** from the App Credentials page. Paste the **Client Secret** from the App Credentials page. After saving, Serval displays it obfuscated - bullet dots with only the last 4 characters visible. When editing an existing Zoom connection, re-enter the complete set of values - Account ID, Account Name, Client ID, and Client Secret - before saving. Do not clear pre-filled fields or leave any field blank, even when you are only rotating the Client Secret, so the connection is always saved with a full, valid credential set. ## Verifying the connection Zoom does not surface named health checks in Serval - there is no built-in connection test with success or failure messages. The most direct way to confirm the connection works end-to-end is to run one of the shipped read-only workflows (for example, **List Zoom Meetings** for a known user) and check that it returns results. A connection that mints tokens successfully can still fail individual workflows with permission errors. That almost always means a scope is missing on the Server-to-Server OAuth app in Zoom - add the scope there (not in Serval) and re-run; the next token picks it up automatically. ## Gotchas and troubleshooting Serval does not request OAuth scopes during connection - the token carries exactly the scopes enabled on your Server-to-Server OAuth app in the Zoom App Marketplace. If a workflow fails with a scope or permission error, add the missing scope to the app in Zoom; reconfiguring the connection in Serval will not help. The delegate workflow specifically needs the user write admin, phone read admin, and phone write shared setting admin scopes. When you edit the Zoom connection settings, do not clear or blank out any pre-filled fields. If you are rotating the Client Secret (or changing any value), re-enter the full credential set - Account ID, Account Name, Client ID, and Client Secret - before saving, so the connection is updated with a complete, valid set of values. Zoom list endpoints return one page at a time along with a "next\_page\_token" value. A custom workflow that reads only the first response silently truncates results. Loop until the token comes back empty or absent, typically with a page size of 300. The shipped list and attendance-report workflows already paginate this way. Zoom is a multi-product integration. Every API call must go through one of the three submodules - `zoom.users.apiRequest`, `zoom.meeting.apiRequest`, or `zoom.rooms.apiRequest` - there is no top-level `zoom.apiRequest`. Meeting reports (past meetings, participants, attendance, Q\&A) live under `zoom.meeting`. All three submodules send requests to Zoom's v2 API base, and the integration's typed paths are written without the v2 prefix. Do not add the prefix yourself when building custom workflow requests - it would be applied twice. On the settings page, the saved Client Secret is displayed with all but the last 4 characters replaced by bullet dots. This is normal obfuscation, not corruption. To change the secret, paste the actual new value. *** Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Zoom integration. # Zscaler Source: https://docs.serval.com/sections/integrations/zscaler Connect Zscaler OneAPI to Serval with a ZIdentity API client so workflows can review ZIA, ZPA, Client Connector, and ZDX data live. ## About Zscaler Zscaler is a zero trust security platform for internet access, private access, digital experience, and cloud security. Serval connects through Zscaler OneAPI using a ZIdentity API client, then runs workflows against your tenant on demand. **Authentication:** OAuth 2.0 client credentials from ZIdentity. Serval stores your Client ID, Client Secret, vanity domain, and cloud setting, then exchanges them for short-lived access tokens during workflow runs. **Data sync:** on demand only. Serval does not run a background sync for Zscaler; workflows call OneAPI live. ## What the Zscaler integration enables | Capability | Description | | - | - | | Review ZIA status | Check whether ZIA configuration is active or waiting for activation. | | Audit ZIA admins and roles | List administrator users and role summaries for access reviews. | | Export ZIA audit logs | Create, check, and download administrator audit log reports for a chosen time range. | | Inspect ZIA policy inventory | List locations and URL categories used by ZIA policy. | | Inspect ZPA inventory | List ZPA customers, application segments, segment groups, server groups, app connectors, and posture profiles. | | Support Client Connector | List enrolled devices by user and retrieve device OTPs such as `ziaDisableOtp`. | | Troubleshoot with ZDX | Find a user's ZDX devices, read device details and health metrics, list monitored applications and their scores, and list ongoing alerts. | ## Get your credentials You need a ZIdentity API client with access to the Zscaler APIs your workflows will call. In ZIdentity, create an API client for Serval or choose an existing automation client. Add the ZIA, ZPA, Client Connector (ZCC), and Digital Experience (ZDX) API resources required for the workflows you plan to run. Start with read-only access for inventory workflows. Device OTP retrieval needs ZCC access that can return OTP secrets. ZDX workflows need a ZDX Advanced or Advanced Plus subscription. Copy the Client ID and Client Secret. Store the Client Secret before leaving the creation screen. Record the vanity domain prefix from your token URL. For `https://acme.zslogin.net/oauth2/v1/token`, enter `acme` in Serval. If you plan to run ZPA workflows, copy the ZPA customer ID from the ZPA Admin Portal. ## Connect in Serval In Serval, open the Zscaler integration and start a new connection. Use a name like `Production` or `Corporate`. Enter only the vanity prefix, such as `acme`. Leave this blank for production. Enter values like `beta` or `alpha` only when your Zscaler tenant uses that OneAPI cloud. GOV and GOVUS tenants are not supported by Zscaler OneAPI. Paste the ZIdentity Client ID and Client Secret. Enter the ZPA customer ID and microtenant ID if you want them stored on the connection. ZPA workflows also ask for the customer ID explicitly. ## Verifying the connection Serval runs five health checks against your Zscaler connection. The first one tells you which stage failed, so read its message before changing anything. **Validate Zscaler OneAPI Connection** - exchanges the stored ZIdentity client credentials for an access token, then reads ZIA status. * Pass: "Successfully connected to Zscaler OneAPI." * Fail, token exchange: Serval couldn't obtain an access token, so OneAPI was never called. Verify the vanity domain, Client ID, and Client Secret. The message includes the ZIdentity error code, such as `invalid_client`, when ZIdentity returns one. * Fail, host unreachable: Serval couldn't connect to the OneAPI host. Check the connection's cloud value. * Fail, ZIA rejected the token (HTTP 401): the token was issued, but the API client isn't granted the ZIA resource in ZIdentity, or the connection's cloud value doesn't match the tenant. This is expected on a connection that only serves ZDX, ZPA, or Client Connector workflows. **List Zscaler Admin Users**, **List Zscaler Admin Roles**, and **List Zscaler Locations** - confirm the API client can read ZIA administrators, roles, and locations. On an API client without the ZIA resource, all three fail with the same "not granted the ZIA resource" message as the first check. **List ZDX Departments** - lists the configured ZDX departments, which confirms the API client is granted the Digital Experience (ZDX) resource and the tenant has a ZDX Advanced or Advanced Plus subscription. On a connection that isn't used for ZDX, this check fails and says so. Switch it off for that connection so the connection is no longer flagged as unhealthy. ZPA and Client Connector have no dedicated health check. Run one of their workflows to confirm the API client's resource grants. On an API client granted only the ZDX resource, **List ZDX Departments** passes while the four ZIA checks fail with the "not granted the ZIA resource" message. The connection works for ZDX workflows. Grant the ZIA resource only if you plan to run ZIA workflows. ## Client Connector device OTPs To retrieve a ZIA disable OTP or related Client Connector OTP for a user device: 1. List enrolled devices, optionally filtered by username, and copy the device `udid`. 2. Request OTPs for that `udid`. The response can include `ziaDisableOtp`, `exitOtp`, `logoutOtp`, `uninstallOtp`, and related values. Device OTP retrieval requires installer approval because the returned values can disable Client Connector protections. ## Digital Experience (ZDX) ZDX workflows run against the same OneAPI connection once the ZIdentity API client has the ZDX resource. Start with **Find ZDX Devices for User**, which resolves a requester's active devices by email, then pass a returned device ID to the device detail and health metric workflows. Most ZDX endpoints cover the last 2 hours of data. If your tenant still holds a legacy ZDX API key, the separate [Zscaler ZDX (Legacy API Key)](/sections/integrations/zscaler-zdx) integration continues to work. Zscaler does not offer legacy ZDX keys on tenants that never had one, so new ZDX connections should use this integration. ## Audit log reports Serval can create a ZIA administrator audit log report for an epoch timestamp range, check the report generation status, and download the latest generated report. Creating a new ZIA audit log report overwrites the previous generated report in Zscaler. These workflows use Zscaler's audit report API. They do not replace NSS, LSS, or Cloud NSS streaming for web, firewall, DNS, or ZPA activity logs. ZPA workflows require a ZPA customer ID. The ID is part of each ZPA request path and is not interchangeable with the Serval integration ID or ZIA organization IDs. # Zscaler ZDX (Legacy API Key) Source: https://docs.serval.com/sections/integrations/zscaler-zdx Connect Zscaler Digital Experience to Serval with a legacy ZDX API key. Tenants on ZIdentity should connect ZDX through the Zscaler OneAPI integration instead. ## About Zscaler ZDX (Legacy API Key) Zscaler Digital Experience (ZDX) monitors end-user experience from the device outward: application scores, device health, network paths, and alerts. This integration authenticates with a **legacy ZDX API key** (Key ID and Key Secret from the ZDX Admin Portal). Zscaler now serves ZDX through OneAPI, and tenants that never created a legacy key cannot create one today. If your Zscaler tenant uses ZIdentity API clients, connect ZDX through the [Zscaler](/sections/integrations/zscaler) integration instead: grant the API client the ZDX resource and the ZDX workflows run on that connection. Existing connections made with this integration keep working and need no migration. A legacy ZDX API key cannot call ZIA, ZPA, or Client Connector endpoints, and a ZIdentity API client cannot authenticate to this integration. Use the Zscaler integration for both when your tenant is on ZIdentity. **Authentication:** ZDX API key. Serval stores your Key ID and Key Secret, then exchanges them for short-lived tokens during workflow runs. The Key Secret itself is never sent to Zscaler — only a hash derived from it. **Data sync:** on demand only. Serval does not run a background sync for ZDX; workflows call the ZDX API live. ## What the Zscaler ZDX (Legacy API Key) integration enables | Capability | Description | | - | - | | Look up users and devices | Find a user's active devices by name or email, with hardware, network, and software details. | | Read application scores | List monitored applications with ZDX scores, score trends, and metric trends such as Page Fetch Time or latency. | | Inspect device health | Read a device's CPU, memory, disk, network, and Wi-Fi health metrics, plus configuration change events. | | Review probes | List web and Cloud Path probes per device and application, including hop-by-hop path data. | | Triage alerts | List ongoing and historical alerts and the devices each alert affects. | | Run deep traces | Start, poll, and stop deep trace sessions on a device, and read captured top processes. | | Analyze scores | Start and read ZDX score analyses for an application on a device. | | Audit software inventory | List software across the tenant and the users and devices that have a specific package installed. | ## Get your credentials You need a legacy ZDX API key that already exists on your tenant, or a tenant where the API Keys page still offers key creation. ZDX API access requires a ZDX Advanced or Advanced Plus subscription. In the ZDX Admin Portal, go to Administration and open API Keys. Create a new API key. Copy the Key ID and the Key Secret — store the Key Secret before leaving the screen. Record the cloud name from your ZDX tenant URL: `zdxcloud`, `zdxbeta`, or for government tenants `zdxgov` (FedRAMP Moderate) or `zdxten` (FedRAMP High). Most tenants are on `zdxcloud`. ## Connect in Serval In Serval, open the Zscaler ZDX (Legacy API Key) integration and start a new connection. Use a name like `Production` or `Corporate`. Paste the ZDX Key ID and Key Secret. Leave this blank for `zdxcloud`. Enter `zdxbeta`, `zdxgov`, or `zdxten` only when your tenant is on that cloud. ## Verifying the connection The Zscaler ZDX (Legacy API Key) integration ships health checks that validate authentication and list applications, devices, and ongoing alerts. If a check fails, verify the Key ID, Key Secret, and cloud name, and confirm your subscription includes ZDX API access. ## Time ranges and pagination Most ZDX read endpoints default to the last 2 hours when no `from`/`to` range is given; timestamps are Unix epoch seconds. Historical alerts are limited to a 14-day range. List endpoints return a `next_offset` cursor — pass it back as `offset` until it is null. Deep traces and score analyses create activity on the target device and count against ZDX processing quotas, so workflows that start them should stop or delete sessions they no longer need. # April 1, 2026 Source: https://docs.serval.com/sections/release-notes/Apr-1-2026 This release includes a redesigned ticketing interface, SLA workflow triggers, installable workflow bundles, an approvals API for custom follow-up logic, Coupa integration, and domain filtering controls. ## **Highlights** * [Redesigned Ticketing Interface](#redesigned-ticketing-interface) * [Trigger Workflows from SLA Events](#trigger-workflows-from-sla-events) * [Install Multiple Workflows at Once with Bundles](#install-multiple-workflows-at-once-with-bundles) * [Customize Approval Follow-Ups with the Approvals API](#customize-approval-follow-ups-with-the-approvals-api) * [Connect Coupa to Serval Workflows](#connect-coupa-to-serval-workflows) * [Manage Organization Security Settings](#manage-organization-security-settings) ### **Redesigned Ticketing Interface** The ticketing interface has been rebuilt on a new visual foundation. The redesign improves information density, makes queues easier to scan, and renders correctly at any screen size. It also ships the first production components from Serval's 2026 design system, which will continue rolling out across the product in upcoming releases. **View updated Slack cards with progress indicators** Slack cards for ticket and workflow activity have been updated with clearer structure and inline progress indicators. More context surfaces in the card so users can act without leaving Slack. Slack thread with a Serval Request Summary card showing ticket status and inline workflow progress steps ### **Trigger Workflows from SLA Events** You can attach workflows to SLA definitions so automations run from your SLA configuration without separate wiring. Those actions are **time-based only**: each one fires at an **offset from the SLA breach time** (before the breach, exactly at breach, or after). They are not tied to other ticket events such as messages or status changes. Use this to escalate to a manager as the clock runs down, alert a Slack channel before time expires, or reprioritize tickets automatically ahead of breach. *For example, configure a workflow that pings the on-call channel 30 minutes before a critical ticket breaches SLA and assigns it to the team lead if no one has responded yet.* ### **Install Multiple Workflows at Once with Bundles** Workflows in the catalog can now be grouped into bundles and installed all at once. Instead of adding each workflow individually, install a complete set — all onboarding workflows, all access management workflows, all integrations for a given tool — in a single action. This makes it faster to set up a new team, deploy a standard automation suite across your org, or get started with a new integration's full workflow library. ### **Customize Approval Follow-Ups with the Approvals API** The Approvals API now lets you define what happens after an approval resolves. When a request is approved or denied, you can trigger a workflow, provision access, send a notification, or push the outcome to an external system — based on the decision, who made it, and any data submitted with the request. This is useful for chaining approval workflows together, triggering provisioning only after a specific approver signs off, or building approval-dependent automations that connect Serval to other tools in your stack. ### **Connect Coupa to Serval Workflows** Coupa is now a native Serval integration. Connect it to build workflows that read from and write to Coupa, route procurement-related requests, and incorporate Coupa approval data into help desk automations. Teams that use Coupa for procurement and finance can now handle related IT requests — vendor access, license provisioning, cost center routing — directly through Serval. ### **Manage Organization Security Settings** Under **Organization Settings** → **Security**, org admins configure **SSO** (connection status, domain verification, and the **Require SSO** toggle), **SCIM** for user and group provisioning from your identity provider, and the **domain allowlist** with **domain filtering** so only matching email domains are in scope when people sync from connected directories and integrations. See [Organization settings and security → Security: SSO, SCIM, and domains](/sections/documentation/platform/org-settings#security-sso-scim-and-domains) for paths, each control, and how enforcement works. This release adds **Enforce Domain Filter** at the bottom of the domain allowlist card. Configure allowed domains, save, then use **Check Users** to dry-run who would be deactivated. The dialog shows counts and affected people before you commit. Confirm there to deactivate every non-matching user in one action. The signed-in admin is never deactivated. Users removed by enforcement stay deactivated while domain filtering stays on; they cannot be reactivated until policy changes allow it. *For example, an IT admin cleaning up access after an acquisition can preview which contractor accounts fall outside the approved domain list, review the results, and deactivate them all without touching each account individually.* *** ## **Installable Workflows** **Add users to Slack channels from the workflow catalog** A new installable workflow lets you add a user to a Slack channel directly from Serval. Previously only available in the admin app, this workflow is now in the standard catalog for all users. *** ## **Integrations** **Connect Spotify to Serval workflows** Spotify is now available as a native integration. Build workflows that control playback, search tracks, and manage playlists from Serval. See the [Spotify integration docs](/sections/integrations/spotify) for setup. **Connect Coupa to Serval workflows** See Highlights above. *** ## **Platform** **Filter MCP tools dynamically** Administrators now have more control over which MCP tools are exposed in a given context with dynamic MCP filtering. **Create and list messages via the public API** New public API endpoints support creating and listing messages on tickets programmatically. Use them to post to ticket threads or pull message history from integrations and reporting tools without using the web app. # April 22, 2026 Source: https://docs.serval.com/sections/release-notes/Apr-22-2026 Pause workflows for approval, compose email replies with citations, manage Anthropic usage, install Google Workspace workflows, and connect Tanium plus new endpoint integrations. ## Highlights * [Pause a workflow mid-run to collect an approval](#pause-a-workflow-mid-run-to-collect-an-approval) * [Broadcast to Slack channels from incident tickets](#broadcast-to-slack-channels-from-incident-tickets) * [Manage Anthropic usage from Serval](#manage-anthropic-usage-from-serval) * [Compose email responses with citations](#compose-email-responses-with-citations) * [Schedule a start time for access requests](#schedule-a-start-time-for-access-requests) ### Pause a workflow mid-run to collect an approval Workflows can now pause mid-run and wait for a human approval before continuing, using the new `requestApproval` action. The workflow holds at that step until a designated approver responds — in Slack, Teams, email, or the Serval web portal — then resumes automatically. This makes it possible to build end-to-end automated workflows that still require a decision at a specific point, without splitting the logic across multiple workflows or relying on a separate ticketing step. Budget sign-offs, access escalations, security reviews, and multi-stage provisioning are the immediate use cases. **Examples** * A workflow handles a Claude access request: it runs initial checks, then pauses with `requestApproval` so a manager can approve adding a paid Anthropic seat. After approval, the same run continues, triggers an access request for Claude in Serval, and later steps finish provisioning once that request is approved. * A workflow that adds someone to a sensitive Google Group looks up the group owner in Workspace, pauses with `requestApproval` until that owner approves the membership change, then applies the update. * The same Google Group change can resolve the requester from HRIS, walk the reporting chain to VP or above, pause for that approver, then continue once they respond. Learn more in the [approvals documentation](/sections/documentation/workflows/Configure/approvals#mid-run-approvals). ### Broadcast to Slack channels from incident tickets Incident tickets now have a broadcast button that sends a message to a Slack channel directly from the ticket thread. Stakeholders get consistent updates during active incidents without IT leaving Serval or manually copying ticket details into Slack. *For example, during a production outage, the IT team can push status updates to #it-incidents and #engineering-alerts from the ticket in two clicks, keeping the right people informed without losing their place in the resolution flow.* ### Manage Anthropic usage from Serval Serval now integrates with the Anthropic Admin API, giving IT teams a way to manage Claude usage directly from Serval workflows. You can provision seats, revoke access, and monitor consumption without leaving your IT system. The integration ships with 19 installable workflows covering the most common Admin API operations. *For example, when an employee is offboarded, a Serval workflow can automatically revoke their Claude seat alongside their Okta and GitHub access in a single run, keeping your AI tooling in sync with the rest of your stack.* ### Compose email responses with citations The email reply experience is generally available for teams that use email intake. The ticket composer adds **To** and **Cc** rows above the message body for public replies (internal notes stay unchanged). The To line is prefilled from the latest inbound sender so agents do not have to copy addresses from the thread. The Cc line starts from current ticket subscribers. Add or remove people in Cc, send the reply, and Serval updates subscribers to match, so the ticket’s audience stays aligned with who was copied on email. On each email-sourced message in the timeline, Serval shows an inline To and Cc citation block with the original routing. Recipients resolve to people in your org when Serval can match the address, including your intake address, so agents see who was on the thread at a glance. Long lists can expand and collapse. *For example, when a requester loops in their manager on an email thread, the citation shows both addresses in the message header. The agent replies once with the manager still on the Cc line, and the ticket keeps everyone in sync without retyping addresses.* ### Schedule a start time for access requests Access requests now support a scheduled start time. Requesters specify when they need access to begin, and Serval provisions it at that time rather than immediately upon approval. *For example, a contractor starting a project next Monday can request access today — their accounts activate on the right day without IT having to remember to run provisioning manually.* Learn more in the [end-user access documentation](/sections/documentation/end-user/end-user-access#scheduling-a-start-time). *** ## Workflows **Preview a workflow form before publishing** A new preview button in the workflow builder lets you see the form exactly as a requester will before publishing. Catch layout and field issues without running a test submission. **Customize approval follow-ups with the approvals API** The approval requests API now supports custom logic on follow-up actions. After an approval is granted or denied, a workflow can run automatically: send a confirmation, provision an entitlement, update a record in a connected system, or trigger any downstream action. **Permanently delete tickets** Tickets can now be permanently deleted from the ticket action menu. After deletion, Serval routes you back to the ticket list rather than landing on a 404. *** ## Access management **Team managers can create, update, and delete entitlements** The team manager role now includes full CRUD permissions for entitlements, giving managers more control over their team's access catalog without requiring org admin access. *** ## Ticketing **Get ticket details in your Serval Slack DM** When a ticket is created, Serval sends a structured message to the requester's Serval Slack DM with ticket details, current status, and a link to the full ticket. Requesters have one place to track their requests without going to the web app. **Slack messages link back to the original request** Workflow approval messages and other Serval Slack notifications now include a link back to the original Slack message that triggered the request, making it easier to trace where an action started. **See the source group in picklist fields** Picklist fields now display the source group alongside each option, giving agents more context when selecting values. *** ## Integrations This release also includes the Anthropic Admin API integration, covered in Highlights above. **Tanium** Tanium is now available as a native Serval integration. IT and security teams can query endpoint data, trigger remediation actions, and pull Tanium's visibility directly into Serval workflows alongside tickets and access data. *For example, when an employee reports a slow machine, the Help Desk Agent can surface real-time endpoint health data from Tanium in the ticket thread, giving the IT agent the context to diagnose and act without switching tools.* **Google Workspace installable workflows** The installable workflow library now includes 15 pre-built workflows for Google Workspace. IT teams can activate them from the Serval catalog without writing any workflow logic. They group into four areas: * **User management:** Retrieve user details, list all users in a domain with search, suspend and unsuspend accounts, reset a password with a temporary credential, and add a user to a group with a specified role. * **Calendar:** List events within a time range and create events with attendees. * **Drive:** Search files by query, get detailed file metadata, share files with users, groups, or domains, remove sharing permissions, and list all shared drives. * **Sheets:** Read data from a range and append rows to a sheet. Browse and install under **Team Settings** → **Workflows** → **Workflow Library**. **Dropbox** Dropbox is now available as a native integration with BYO OAuth app support. **Egnyte** Egnyte is now available as a native integration via OAuth 2.0. **ManageEngine Endpoint Central** ManageEngine Endpoint Central is now available as a native integration. Teams can connect endpoint inventory and device management actions into Serval workflows. **NinjaOne** NinjaOne is now available as a native integration. Teams can bring NinjaOne endpoint operations into Serval workflows and ticket automation. **Add multiple API headers in app integrations** App integrations now support multiple API headers, giving teams more flexibility when connecting to services that require custom authentication or metadata headers. **Connect multiple Datadog instances** Teams with more than one Datadog account can now connect multiple instances to Serval. The integration previously limited each org to a single Datadog connection. **Okta integrations no longer display as legacy** Okta integrations that were incorrectly flagged as legacy now display correctly. Customers can reconnect or refresh scopes without deleting and re-adding the integration. **Action required: re-authenticate Serval's Slack integration** An updated OAuth scope has been added to Serval's Slack app to support new Help Desk Agent features. Some customers will need to re-authenticate the Serval Slack integration. If prompted, follow the re-authentication flow in Serval's integration settings. *** ## Platform **Workflow runs now open in full screen** The workflow runs view has been rebuilt with a responsive layout and full-screen mode. Long-running workflows and complex run histories are easier to read and navigate at any screen size. **Pick a color for your team** Teams now have a color picker in settings. Team colors appear across the Serval UI to help agents distinguish between teams when working across multiple queues. **Assets renamed to Databases** The Assets section has been renamed to Databases across the Serval UI. *** # April 9, 2026 Source: https://docs.serval.com/sections/release-notes/Apr-9-2026 This release includes custom fields for tickets, ticketing UX upgrades, recurring campaigns, new installable workflows for LDAP/AD, Okta, and Google Workspace, control over when Serval prompts for ticket feedback, and a batch of Slack and email reliability fixes. ## **Highlights** * [Add Custom Fields to Tickets](#add-custom-fields-to-tickets) * [Run Campaigns on a Recurring Schedule](#run-campaigns-on-a-recurring-schedule) * [New Installable Workflows](#new-installable-workflows) * [Choose when to request Serval feedback](#choose-when-to-request-serval-feedback) * [Reorder Ticket Statuses and Toggle the Sidebar](#reorder-ticket-statuses-and-toggle-the-sidebar) ### **Add Custom Fields to Tickets** **Custom fields** store structured data on tickets beyond built-in properties like status, priority, and labels—e.g. **cost centers**, **affected systems**, **office locations**, and **request areas**. **Team admins** add them under **Settings → Custom Fields**; each field applies to **all tickets** on that team. Types include **text**, **number**, **boolean**, **date**, **dropdown**, and **multi-select**. Agents fill them in the **Custom Fields** section on the ticket detail right panel (you can add fields from there too). Turn on **AI Custom Field Inference** and Serval proposes values from the ticket text for every type **except date** (use a workflow for automatic dates). **Workflows** and the **public API** can also read and write values. In the ticket list, open **Filter** and pick a custom field: predefined options for dropdowns and multi-selects, search terms for text, comparison operators for numbers and dates. See [Custom fields](/sections/documentation/ticketing/ticket-configuration/custom-fields) for supported types, creating fields, AI inference, filtering steps, deprecation, and API examples. *For example, pair a **Request Area** dropdown (`Hardware`, `Network`, `Software`) with a **Cost estimate** number field, let inference suggest **Affected systems** from the thread, then filter to **Hardware** and cost estimates under 5,000 for fast triage.* ### **Run Campaigns on a Recurring Schedule** Campaigns can now be **recurring** as well as one-time. Set a repeating cadence—such as every few hours, on selected weekdays, on specific days of the month, or on particular months—and Serval creates a new **run** each time the schedule fires. Activate the series to start the schedule; each run has its own delivery lifecycle and appears on the parent campaign’s **Runs** tab. Choose whether the first run starts right away or waits for the next cycle, pick **specific timezone** or **local time** delivery where supported, and use the schedule preview to confirm upcoming send times before you go live. See [Scheduling](/sections/documentation/campaigns/scheduling) for every option, including frequency types and how recurring runs relate to the parent campaign. ### **New Installable Workflows** New installable workflows are available in the catalog: * **LDAP / Active Directory — Get AD Extension Attributes for User** — Look up a user in on-premises AD over LDAP and return extension attributes, distinguished name, and `sAMAccountName` when present. * **Okta — Send Okta Activation Email** — Send an activation email (or return an activation link) for a user in staged or deprovisioned status by activating their lifecycle. * **Google Workspace — Export Google Group Members to CSV** — Export a group’s members to CSV (emails, names, roles, types), with optional Slack upload and ticket context when the integrations are connected. Install them from the workflow catalog in your Serval admin settings. ### **Choose when to request Serval feedback** Under **Request feedback** in team settings, **"Request feedback for Serval when"** is a new choice: ask for Serval ratings on **"Meaningful tickets"** only (two or more AI responses or a workflow ran on the ticket) or on **All tickets** (every resolved ticket). Everything else on that page—request frequency, who feedback is about, question format—is unchanged; this only adds control over *when* Serval-triggered feedback runs. *For example, a team that wants ratings only when Serval actually helped can pick Meaningful tickets and avoid prompting users after bare handoffs with no AI or workflow involvement.* ### **Reorder Ticket Statuses and Toggle the Sidebar** Ticket statuses can now be reordered to match how your team actually works. Drag them into the sequence that fits your queue instead of working around a fixed order. The ticket sidebar can be toggled on or off for a cleaner view when you need more screen space. Forwarded messages also have an updated visual style that makes the source of a forwarded thread easier to read at a glance. *** ## **Ticketing** **Routing improvements with better visibility** Cross-team routing now surfaces more detail about why each routing decision was made. Agents and admins can see the reasoning behind assignments, making it easier to validate and tune routing rules over time. **Clearer warnings when editing shared access policies** The access policy dialog now shows a more prominent warning when the policy you are editing is used by other apps. Before, it was easy to modify a shared policy without realizing the change would affect multiple connected applications. The dropdown and dialog layout have also been updated for easier navigation. *** ## **Integrations** **Manage app resources via MCP tools** MCP tools now support full create, read, update, and delete operations on app resources. Developers and power users can manage app resources programmatically through a connected AI assistant. *** # August 7, 2026 Source: https://docs.serval.com/sections/release-notes/Aug-07-2026 Create dynamically-rendered forms, view journeys as dependency graphs, and create multiple email intake addresses per team. ## Highlights * [Create dynamically-rendered forms](#create-dynamically-rendered-forms) * [More control over email intake](#more-control-over-email-intake) * [Visualize a journey as a dependency graph](#visualize-a-journey-as-a-dependency-graph) ### Create dynamically-rendered forms Forms are now a first-class resource within Serval and can be found under Service Management in the sidebar navigation. Like workflows, forms are TypeScript code underneath, can be built by Catalyst, and version upon publish. You can build a form by simply describing the inputs and format to Catalyst, or tell Catalyst to build a form against an existing workflow. Form fields can appear, become required, or change their options based on earlier answers, and a form can run a workflow while it's still open to look up live data. Forms can also support field types like file uploads, database records, and Serval users. The same form renders in the catalog, inside a ticket, and as a Slack modal, so employees fill it out wherever they already are. *For example, a hardware request form can check live inventory as the employee picks a laptop, or show shipping fields only when they choose to ship it home.* Learn more in [Forms](/sections/documentation/forms/overview). ### More control over email intake A team can now have several email intake addresses, each with its own auto-response behavior, and you can filter ticket views and write routing rules by the address a request came in on. Replies also support a configurable footer and rich-text and HTML authoring, so outbound email looks the way you want. See [Email](/sections/documentation/helpdesk/email) for setup. ### Visualize a journey as a dependency graph Journeys can now be viewed as a dependency graph instead of a flat task list. The graph lays out tasks in the order they actually depend on each other, so you can see what's blocking what at a glance. Users can toggle between the graph and the task list view on the journey overview page. *** ## Ticketing **Save ticket views to visibility groups** A ticket view can now be saved to a visibility group, so a whole group shares the same saved view instead of each person rebuilding it. **Show or hide journey tickets in a team's list** A team's ticket list now has toggles to include or exclude journey tickets, so onboarding and offboarding work doesn't crowd out day-to-day requests. **Richer conditions for routing, visibility, and SLAs** Assignment routing rules, ticket visibility, and SLA policies now support richer conditions. Any condition that matches a value can be inverted with is-not, and rules can match on a requester's custom user fields as well as the ticket's own. **Cancel SLAs when a ticket leaves the queue** Active SLAs are now canceled when a ticket is archived, trashed, or moved to another team, so timers stop counting against work that's no longer in the queue. ## Knowledge **See when a sync didn't cover the whole source** A connected source now flags when a sync finished without reaching all of its content, so partial coverage is visible instead of silent. **Know when a source has blocked locations** Knowledge sources now surface when some locations were blocked during sync, so you can tell why certain content never made it in. ## Integrations **New and expanded connectors** Serval adds the [SAP LeanIX](/sections/integrations/sap-leanix) connector, adds per-user OAuth for [SailPoint Identity Security Cloud](/sections/integrations/sailpoint-identitysc), and expands the AWS connector with WorkSpaces and Resource Groups Tagging support. **Custom headers on OAuth connections** Custom connections that authenticate with OAuth client credentials can now send additional custom headers on every request. ## Workflows **Multi-stage approvals in workflows** Workflow approvals now run in stages. A workflow can pause mid-run and collect sign-off from several approvers in sequence, where each stage must clear before the next begins, and steps within a single stage are gathered in parallel. See [Workflow approvals](/sections/documentation/workflows/Configure/approvals). **Rotate a webhook trigger's secret without downtime** You can now rotate the secret on a webhook trigger in place, with a grace window during which both the old and new secrets work, so live integrations keep firing while you roll the secret. ## Databases and users **Stop directory sync from creating new users** When a connected identity or resource source syncs, it can create Serval users for accounts it discovers. Org admins can now turn that off per connection, so a sync updates and links the people you already manage without minting brand-new accounts for everyone it sees. See [Connect an identity provider](/sections/access-management/configuration/connect-idp). **Saved views for databases** You can now save filtered views of a database and switch between them with view pills, so common cuts of your data are one click away. **Manager as a built-in field across the Users database** A user's manager is now a first-class built-in field wherever the Users database appears, including filtering, columns, and export. ## For developers **EU tenant support in Serval CLI** Serval CLI v0.5.7 adds EU tenant support, so you can sign in to and push and pull configuration in the EU region from the command line. See [Signing in to another region](/sections/cli/push-pull-configuration#signing-in-to-another-region). # August 14, 2026 Source: https://docs.serval.com/sections/release-notes/Aug-14-2026 Org charts and reporting lines, on-demand ticket translation, SLA policy groups, sharable access reviews, and larger campaign audiences. ## Highlights * [See your org chart and reporting lines](#see-your-org-chart-and-reporting-lines) * [Connect agent-to-agent (A2A) endpoints](#connect-agent-to-agent-\(A2A\)-endpoints) * [Translate a ticket's conversation](#translate-a-tickets-conversation) * [Run several SLAs of the same type on one ticket](#run-several-slas-of-the-same-type-on-one-ticket) * [Copy external knowledge into a native knowledge base](#copy-external-knowledge-into-a-native-knowledge-base) ### See your org chart and reporting lines Serval now builds an org chart from your connected IdP. Every user's detail page shows a reporting-line rail with the people above and below them, and a dedicated Org chart page on the Organization workspace lets you navigate the whole reporting structure. Manager, department, and job title are all synced user fields from your IdP and can be edited inline. See [User profile fields](/sections/api-reference/user-profile-fields). ### **Connect agent-to-agent (A2A) endpoints** You can now connect an external AI agent over the A2A protocol. Serval reads the agent's card, tells you which authentication it requires as you set the connection up, and supports OAuth client credentials for the connection. ### Translate a ticket's conversation Agents can now translate a ticket's conversation into their own language, on demand, without leaving the ticket. Turn translation on for the thread and Serval machine-translates each message into your language. Translation covers any language Serval supports. See [Resolving tickets](/sections/documentation/ticketing/resolving-tickets). ### Run several SLAs of the same type on one ticket SLA policies can now be grouped, so a single ticket can run several SLAs of the same metric at once instead of just one. Each policy in a group defines its own pause behavior, letting you measure the same target under different rules side by side. *For example, track a resolution SLA that counts all elapsed time alongside one that pauses while you are waiting on the requestor, all on the same ticket.* See [SLA policies](/sections/documentation/ticketing/ticket-configuration/slas). ### Copy external knowledge into a native knowledge base You can now copy a single external page, or an entire folder, from a connected source into a native Serval knowledge base, straight from the page-level menu on read-only external content. Previously "Copy to Serval" only worked on a whole base, so pulling one useful article out of a connector meant duplicating the entire base. Now you can lift out just the pages you want to own and edit natively. *For example, copy one Confluence runbook into your team's native knowledge base and edit it in Serval without importing the whole space.* See [Connect knowledge sources](/sections/documentation/knowledge-base/connected-sources). *** ## Ticketing **SLA conditions on the assignment group** An SLA policy can now attach based on a ticket's assignment group, so different groups can be held to different targets. **Agents can override a status transition** Agents with the right permission can now override a ticket's status-transition rules to move it to a status the workflow would otherwise block. See [Ticket statuses](/sections/documentation/ticketing/ticket-configuration/statuses). **Derive a major incident from an incident** You can now derive a major incident from an existing incident. Serval creates a new major incident, linked to the source and pre-filled with its context, so you don't rebuild it from scratch. **Email replies that drop the requester become internal notes** When an email reply no longer includes the requester, Serval now records it as an internal note rather than a public reply, so a side conversation between agents stays private. ## Knowledge **Answers in the requester's language** When a requester's language isn't English, the help desk agent now retrieves and answers from the knowledge article written in their language when one exists, falling back to the English original otherwise. ## Access management **Entitlement users tab** An entitlement now has a users tab that shows one row per user, expandable into the groups that grant them access, with pagination, server-side search, and CSV export. You can also revoke a user's access directly from their profile. ## Integrations **Deeper ServiceNow sync** Serval now stamps its "Filed via Serval" correlation on ServiceNow records the moment you link them, surfaces the ServiceNow ticket number in the ticket side panel, and attributes record-producer submissions to the right requester. ServiceNow can also sync the users an ACL criterion matches. See [ServiceNow](/sections/integrations/servicenow). **Real-time Freshservice ticket sync** A new ticket-create webhook brings Freshservice tickets into Serval the moment they're created, instead of waiting for the next scheduled sync. See [Freshservice](/sections/integrations/freshservice). ## Catalyst **See your manual edits in the session timeline** When you edit a workflow, skill, or other resource by hand during a Catalyst session, those edits now appear as compact activity rows in the session timeline, so the history reflects everything that changed, not just what the agent did. ## Databases and users **Turn user sync on or off from the Users database** You can now enable or disable a user-sync source directly from the Users database page, without opening each connection's settings. ## For developers **Public API additions** The public API gains several new capabilities: filter ticket search by parent ticket, count workflow runs and include child runs or runs with a linked ticket in run search, filter groups by user, and read team-group role bindings. # August 21, 2026 Source: https://docs.serval.com/sections/release-notes/Aug-21-2026 General availability of Catalyst, redesigned approval flow builder, improved Slack app home tab, scoped API keys, and custom priority names. ## Highlights * [Catalyst is now generally available](#catalyst-is-now-generally-available) * [Redesigned approval flow builder](#redesigned-approval-flow-builder) * [Improved Slack app home tab](#improved-slack-app-home-tab) * [Custom priority names](#custom-priority-names) * [Scoped API keys](#scoped-api-keys) ### Catalyst is now generally available Catalyst, Serval's automation agent, is now generally available and on by default for every team. It replaces the standalone workflow builder as the primary way to build and publish automations. Describe what you want in natural language and Catalyst drafts the workflow, skill, dashboard, journey, or access setup for you to review, test, and publish, all from one chat. You can also ask Catalyst to suggest and build automations based on your ticket history and connected integrations. *For example, ask Catalyst to analyze the past two weeks of tickets, identify tickets that were escalated to human agents, and build the automations needed to resolve them.* Learn more in [Catalyst overview](/sections/documentation/catalyst/overview). ### Redesigned approval flow builder Approval procedures are now built as a sequence of steps, and each step asks one or more approvers at the same time: a specific user, a group with a quorum (for example, "4 of 8 must approve"), the requester's manager, or a resource owner. Each step decides whether every approver must say yes or any single approval is enough, and every approver carries its own controls for whether they're notified and whether the requester is allowed to approve their own request. The same builder now powers both workflow approvals and access policy approvals. Approvers can also act without leaving their inbox: a request now carries its full content, including the title, the reason, and any linked records, into Slack, Microsoft Teams, and email. ### Redesigned Slack app home tab The Serval app's home tab in Slack has been rebuilt around what you need to do next. It leads with quick actions to file a new request or request access, both of which now open directly in Slack instead of sending you to the web app. Your work is reported as counts, one row per bucket (pending approvals, tickets you created, tickets assigned to you), each with a drill-down that opens a filterable, paginated modal. Your single most urgent item is promoted to full detail so you can act on it in place. *For example, open the Home tab, see "3 approvals waiting," and approve the oldest one without leaving Slack.* See [Interacting with Serval in Slack](/sections/documentation/helpdesk/interacting-with-serval-in-slack). ### Custom priority names You can now rename each of your team's priority levels to match the language your team already uses, straight from Settings. The underlying severity levels stay the same, so nothing about your existing tickets, SLAs, or routing changes. "No Priority" is also now something the help desk agent can choose on its own when a ticket genuinely doesn't need a priority, and you can opt out of that per team. *For example, relabel your priority levels to match your team's naming and let the agent leave a low-touch question with no priority at all.* See [Priorities](/sections/documentation/ticketing/ticket-configuration/priorities). ### Scoped API keys When you create a public API key, you can now give it a name, restrict it to a chosen set of permission scopes instead of full access, and set it to expire. A read-only key is a single choice, or you can pick exactly which scope bundles a key may use. *** ## Ticketing **Group the ticket list by type** You can now group the ticket list by ticket type, alongside the existing grouping options. **Move tickets to another team in bulk** Select several tickets in the list and move them all to another team in one action. **Saved views for an assignment group** A saved ticket view can now be owned by an assignment group, so everyone in that group shares the same views. **Run a workflow when a ticket enters a status** Ticket types that use native status transitions can now run a status entry workflow when a ticket moves into a status. **See why the agent changed a priority** When the help desk agent changes a ticket's priority, it now records and shows the reason for the change. ## Help desk agent **New auto-response variables for email** Custom auto-response emails support two new variables, `{{Ticket-ID}}` for the bare ticket ID and `{{Ticket-Link}}` for a link to the ticket, and now reject unknown variables instead of sending them literally. **Custom intake email host** You can now configure a custom host for your intake email address, so tickets arrive on your own branded MX records. ## Catalyst **Mention knowledge in Catalyst** You can now @-mention a knowledge base item in the Catalyst composer. Catalyst resolves the item for the agent, and native items open in the app. ## Databases **Grant database actions to custom roles** Database actions can now be granted to custom roles, so you can give a role exactly the database access it needs. ## Knowledge **Compare two versions of a knowledge base page** You can now compare any two versions of a native knowledge base page side by side to see what changed. ## Campaigns **Mention people in Microsoft Teams campaigns** Campaign messages sent over Microsoft Teams can now @-mention specific people, just like Slack campaigns. **See when each recipient first replied** A campaign now shows when each recipient first replied, so you can track engagement over time. ## Journeys **Resubmit a completed journey task** A journey task can now be marked to allow resubmission, letting an employee complete it again after it's already done. ## Integrations **New native integrations** Serval adds native integrations for [Recorded Future](/sections/integrations/recorded-future), [Kronos Workforce Central](/sections/integrations/kronos), [Qualys](/sections/integrations/qualys), [Splunk Observability Cloud](/sections/integrations/splunk-observability), [CyberArk Privilege Cloud](/sections/integrations/cyberark-privilege-cloud), [CyberArk PAM (Self-Hosted)](/sections/integrations/cyberark-pam-self-hosted), Nozomi Networks, and Sana. **Sync tickets from Jira Data Center** Serval can now sync tickets from Jira Data Center and Jira Service Management on Data Center. See [Jira Data Center](/sections/integrations/jira-data-center). **Ingest from more than one Jira project** A Jira ticket source can now ingest issues from several Jira projects at once, instead of being limited to a single project. Because Jira workflow and priority schemes are defined per project, Serval stores your status and priority mappings separately for each project you connect, so every project keeps its own field mapping. **Remove a delegated OIDC provider** Admins can now delete a delegated OIDC provider from a custom integration's API settings. ## Platform **Team-scoped notification overrides** Team members can now create their own notification overrides scoped to a team, instead of only org-wide overrides. **Filter audit logs by integration** The audit log can now be filtered by the integration a change relates to. ## For developers **Public API additions** The public API gains several new capabilities: full CRUD for forms, cross-ticket message search, SLA instance data and analytics, an endpoint to trigger an agent run and poll its session status, archive and unarchive for entities, resolving users by email in batch (with `GetUser` no longer failing for deactivated employees), and creating a team's labels. # August 28, 2026 Source: https://docs.serval.com/sections/release-notes/Aug-28-2026 Cross-team KB sharing, custom ticket types, major incident management, and per-field ticket sync. ## Highlights * [Share a knowledge base across teams](#share-a-knowledge-base-across-teams) * [Custom ticket types](#custom-ticket-types) * [Major incident management](#major-incident-management) * [Choose which ticket fields stay in sync](#choose-which-ticket-fields-stay-in-sync) ### Share a knowledge base across teams A team that owns a native knowledge base can now share it with other teams in your organization. Those teams can browse and open the base, and their help desk agent can draw on it when answering tickets. Knowledge written once is available everywhere it's needed, instead of being copied from team to team. *For example, your IT team can share its VPN troubleshooting base with the HR and Facilities teams, and every team's agent answers from the same source of truth.* See [Knowledge base overview](/sections/documentation/knowledge-base/overview). ### Custom ticket types Custom ticket types are now available to every team. Alongside the built-in types, you can define your own in Settings. Each type has its own statuses, custom fields, and filters, so Serval matches how your team already categorizes work. Custom fields can now be organized into named sections, and custom-typed tickets reflect their type throughout the app. *For example, create a "Hardware Request" type with its own fields and status flow, and filter and route those tickets separately from general support.* See [Custom ticket types](/sections/documentation/ticketing/ticket-configuration/custom-ticket-types). ### Major incident management Serval now has first-class support for major incidents. A team manager can promote a ticket into a major incident, which installs a dedicated ticket type with its own ITIL status flow and a promotion workflow to coordinate the response. Serval also detects when several incoming incident reports describe the same underlying problem and automatically groups them under a single anchor incident, so responders see one coordinated picture instead of a pile of duplicates. *For example, when many people report that email is down, Serval groups their reports under one incident, and a manager can promote it to a major incident to drive the response.* See [Incident management](/sections/documentation/ticketing/incident-management). ### Choose which ticket fields stay in sync When Serval syncs a ticket with a connected ticketing system, you can now choose exactly which fields stay in sync. A master toggle turns field sync on or off, and beneath it you can enable or disable individual attributes, so Serval keeps the fields you care about in lockstep and leaves the rest untouched. *For example, keep status and comments in sync with Jira while leaving each system's own priority alone.* See [Ticket syncing](/sections/documentation/ticketing/ticket-configuration/syncing). *** ## Ticketing **One Associated Items section** The ticket side panel now merges directly attached and downstream-impacted items into a single Associated Items section, so everything connected to a ticket lives in one place. **Nest tasks under their parent ticket** Journey and sub-tasks now nest under their parent ticket in the list, and you can collapse a parent to hide its tasks. **Show journeys in team ticket lists** Team ticket lists now include journeys by default, and the Show journeys toggle brings them in or filters them out. **Multi-select values in SLA and assignment criteria** SLA definitions and assignment rules can now match against several values in a single condition instead of one at a time. **Route by group membership** Assignment rules gain a "requester is in group" condition, so you can route tickets based on which group the requester belongs to. **Custom Reply-To for email** Teams can now set a custom Reply-To address for outbound email, separate from the intake address. ## Help desk **Override the help desk agent's name per team** Once an organization enables per-team agent names, a team can override the organization's help desk agent name with its own, so each team's agent introduces itself the way that team expects. **Manage a ticket from Slack** Slack's ticket view now opens a detail modal where you can reply and change status without leaving Slack. A Next button walks you through the ticket list from inside the modal. **Slack DMs name the ticket** Ticket-reply and mention DMs in Slack now include the ticket title in their heading, so it's clear which ticket a message is about. **Turn off Slack workflow cards** Teams can now stop Serval from posting workflow cards in Slack, for channels where those updates add noise. **Progress updates in Teams DMs** The progress indicator card that shows what the agent is doing can now appear in Microsoft Teams direct messages, not just channels. ## Knowledge **Write suggestions into native knowledge** Serval's knowledge suggestions can now create and update pages directly in your native Serval knowledge bases. **Native knowledge bases in the skill picker** When you attach knowledge to a skill, you can now browse and pick native Serval knowledge bases alongside connected sources. ## Platform **Pin pages to the sidebar** Pin the pages you use most to the top of the sidebar for one-click access. **Delegate change management with custom roles** Change management permissions can now be granted through custom roles, so you can give a role exactly the change-management access it needs. **Pick your organization at SSO login** When an email domain maps to more than one Serval organization, users can now choose which one to sign in to at SSO login. ## Integrations **New native integrations** Serval adds native integrations for [Presidio](/sections/integrations/presidio), [Google Cloud Platform](/sections/integrations/gcp), [Jamf Protect](/sections/integrations/jamf-protect), [Jamf Security Cloud](/sections/integrations/jamf-security-cloud), [Splunk](/sections/integrations/splunk), [Brivo Access](/sections/integrations/brivo), [Thinkst Canary](/sections/integrations/thinkst-canary), [CyberArk EPM](/sections/integrations/cyberark-epm), and [Lumos](/sections/integrations/lumos). **Front Lumos access requests** With the Lumos integration, Serval can create, approve, deny, and track Lumos access requests, so employees ask Serval and Serval drives Lumos on their behalf. **Manage PingOne users and groups** The PingID integration can now provision and deprovision PingOne users, and add or remove members from PingOne groups. **Send Office files in ServiceNow live chat** Attachments in a ServiceNow live-agent chat now include Office file types (Word, Excel, PowerPoint), not just images and PDFs. **Connect Typeform in the EU** Typeform connections now offer a Region choice, so accounts on Typeform's EU data center can connect. ## For developers **Public API additions** The public API gains several new capabilities: set a ticket's priority when creating it, create, read, and delete access-profile grants, read endpoints for user relationships, create and manage forms inside folders, read thumbs feedback comments in the feedback feed, and read ServiceNow live-agent interaction IDs on a ticket's external tickets. Catalyst also gains a `MoveTicketToTeam` tool for moving a ticket between teams. # December 10, 2025 Source: https://docs.serval.com/sections/release-notes/Dec-10-2025 This release includes board view for tickets, event-triggered workflows, guidance portal workflow builder, operator-based filtering, and automation suggestion history. ## **Highlights** * [Set Board View for Tickets](#set-board-view-for-tickets) * [Create Workflows Directly from Guidance Portal](#create-workflows-directly-from-guidance-portal) * [Build Serval Event-Triggered Workflows](#build-serval-event-triggered-workflows) * [Add Operator-Based Ticket Filtering](#add-operator-based-ticket-filtering) * [View Historical Automation Suggestions](#view-historical-automation-suggestions) ### **Set Board Layout in Ticket Views** Visualize and organize your tickets with the new board layout. Drag and drop tickets between status columns (e.g., To Do, In Progress, Done, Canceled) and update priority or assignee directly from ticket cards. This intuitive interface makes it easier to track your team's progress at a glance and manage workflows more efficiently. ### **Create Workflows Directly from Guidance Portal** Building comprehensive guidance documentation is now easier. Create new workflows directly within the guidance editor using an integrated side panel, eliminating the need to switch contexts. Additionally, mention and link knowledge base articles in your guidance documents, complete with hierarchical paths and service icons for improved navigation and context. ### **Build Serval Event-Triggered Workflows** Automate tasks in response to specific events with the new event trigger type. Create workflows that respond to Serval events like ticket creation, updates, or new messages. Simply instruct the Workflow Builder to "run the following when there is a new Serval ticket message" or "run the following when there is Serval ticket activity" to set up responsive, asynchronous automations. *For example, build a workflow to send a DM to a specific help desk member every time a VIP submits a ticket to ensure they get priority service*. ### **Add Operator-Based Ticket Filtering** Ticket filtering expands with new operator options across all ticket attributes. Use precise logic like 'is not', 'before', 'on or after', and more when filtering by assignee, dates, requester, team, status, priority, type, and labels. These granular controls help you navigate ticket queues more efficiently and find exactly what you're looking for. ### **View Historical Automation Suggestions** The new "History" tab in automation suggestions provides comprehensive visibility into all past AI-generated suggestions, including those you've accepted or dismissed. This audit trail helps you track and review how Serval has recommended automating tasks and providing guidance over time. ## **Integrations** ### **Expanded Opal Integration** The Opal integration now supports a broader set of operations. This expansion enables more comprehensive interactions with Opal Security for enhanced access management workflows. ## **Platform Improvements** ### **Improved Help Desk Agent Interactions in Email** Serval now intelligently recognizes and threads email replies, even when added to a conversation mid-thread via CC. Reply directly to the automated email confirmation you receive when creating a ticket, and Serval correctly associates your response with the existing ticket. This streamlines communication and ensures all relevant context stays connected. ### **Welcome Message for New Slack Users** New Serval users in Slack now receive a friendly welcome message when they first open the app's Messages tab. This onboarding message introduces Serval's capabilities, explains how to request access or report issues, and provides a quick tip on using the /serval command from any channel. ### **SLA Performance Analytics Dashboard** Track Service Level Agreement compliance with the new SLA performance chart in your analytics dashboard. This visualization shows met versus breached SLAs and supports filtering by various ticket attributes, giving you detailed insights into your team's SLA performance. ## **UI Improvements** ### **Resizable Side Panels** Side panels across Asset Configuration, Asset Ingestion, and the Workflow Browser are now resizable. Drag to adjust panel widths to your preference, and Serval remembers your settings across sessions for a more personalized workspace. ### **Additional UI Refinements** Numerous smaller improvements including consistent ticket status icon sizing, refined mention highlighting in the editor, better ticket board filtering displays, improved task action button clarity, enhanced nested dialog interactions, and streamlined ticket filtering in the analytics dashboard. # December 17, 2025 Source: https://docs.serval.com/sections/release-notes/Dec-17-2025 This release includes light and dark mode, notification preferences, knowledge tagging in guidance, workflow search, event-triggered workflows, and enhanced ticket creation. ## **Highlights** * [View Serval in Light, Dark or System Mode](#view-serval-in-light-dark-or-system-mode) * [Manage Your Help Desk Notification Preferences](#manage-your-help-desk-notification-preferences) * [Tag Knowledge and Browse Workflows in Guidance](#tag-knowledge-and-browse-workflows-in-guidance) * [Search Within Workflow Code Editor](#search-within-workflow-code-editor) * [Select Event-Triggered Workflows in Workflow Dropdown](#select-event-triggered-workflows-in-workflow-dropdown) * [Attach Files and Mention Users When Creating Tickets](#attach-files-and-mention-users-when-creating-tickets) ### **View Serval in Light, Dark or System Mode** Switch between light, dark, and system mode to match your team's preferences. ### **Manage Your Help Desk Notification Preferences** Control where and when you receive notifications. Set team-level defaults for Slack and Email, then create individual overrides for specific event types like approvals, ticket replies, and mentions. Navigate to your team settings, select "..." and click **Notifications** to configure. ### **Tag Knowledge and Browse Workflows in Guidance** Reference knowledge base articles directly in guidance documents so your help desk agent has the right context without searching. Browse and filter workflows by application, tag, and status from the guidance sidebar—no need to switch screens. ### **Search Within Workflow Code Editor** Find specific text, variables, or functions in your workflow code. Navigate and modify complex automations faster. ### **Select Event-Triggered Workflows in Workflow Dropdown** Build workflows that respond to ticket events. Choose from: * **Any ticket activity**: Triggers when a ticket is created or receives a new message * **Ticket created**: Triggers only when a new help desk ticket is created * **New ticket message**: Triggers only when a message is added to a ticket ### **Attach Files and Mention Users When Creating Tickets** Add file attachments and @mention users when creating tickets. Share screenshots or documents upfront so agents have full context from the start. ## **Integrations** **Snipe-IT Integration** Automate IT asset management with the new Snipe-IT integration. Track hardware, manage user assignments, and control inventory directly from Serval workflows. **Google Workspace Group Settings** Manage Google Group settings like membership and posting permissions through Serval. ## **Platform Improvements** **Enhanced Scheduled Workflow Messaging** See run time and status for scheduled workflows. Cancel scheduled workflows instantly—no waiting for sleep states. **Custom Approval Configurations for Installable Workflows** Remove default approvals or set custom configurations for installable workflows. Your preferences stay preserved. ## **UI Improvements** **Workflow Builder Statement Grouping** Consecutive code statements group into single visual nodes. Cleaner workflows that are easier to navigate. **Resizable Ticket Detail Panels** Resize and persist the side panel in ticket details to fit your workflow. # December 4, 2025 Source: https://docs.serval.com/sections/release-notes/Dec-4-2025 This release includes custom approval workflows, semantic workflow search, workflow tagging, shared workflow syncing, and major UI improvements. ## Highlights * [Build Custom Approval Workflows](#build-custom-approval-workflows) * [Schedule One-Time Workflows](#schedule-one-time-workflows) * [Sync Shared Workflows Across Teams](#sync-shared-workflows-across-teams) * [Tag and Organize Workflows](#tag-and-organize-workflows) * [Organize Guidance in the Sidebar](#organize-guidance-in-the-sidebar) ## Build Custom Approval Workflows Automate approval decisions based on your business rules. Route requests to the right approver automatically or approve/deny instantly based on custom logic. Automated decisions show clearer context in both the platform and Slack. Custom approval workflows have three possible outcomes: * **Auto-approve**: Workflow continues until approval is received * **Auto-deny**: Workflow continues until approval is denied * **Manual approval required**: Workflow pauses for manual approval (only primary approvers receive notifications; approval requests include Approve/Deny buttons in Slack) *For example, automatically approve PTO requests under three days but route longer requests to managers. Or determine the right approver based on department, seniority, or budget thresholds.* ## Schedule One-Time Workflows The help desk agent can now schedule one-time workflows when you specify a time. Plan workflow runs in advance, like adding a user to an Okta group when they leave for travel and removing them when they return. Workflows will be run automatically at the times you specify. ## Sync Shared Workflows Across Teams Pull down updates from a central workflow to maintain consistency across teams. When the source workflow changes, Serval shows an "Update Available" button. Click it to pull down changes or dismiss to maintain your version separately. *For example, your IT team creates a laptop provisioning workflow. When HR and Engineering teams use this workflow, they can see a notification in the workflow builder and pull in updates.* ## Tag and Organize Workflows Create custom tags to organize your workflows. Collapse sections in the sidebar and search by tags to find workflows faster. ## Organize Guidance in the Sidebar See "Never Published" and "Disabled" guidance at a glance with new status indicators. Filter to see deleted workflows and understand which guidance is active. ## Platform Updates **Access release notes easily** New Release Notes button in your profile footer for quick access to product updates. **Simplify navigation** Cleaner sidebar labels: "My Tickets" → "Tickets", "My Teams" → "Teams", "My Access" → "Access", "Organization Settings" → "Settings". Navigation paths updated to match (e.g., /my-tickets → /tickets). **Filter and manage tickets** * **"Involves" filter**: One filter for all forms of ticket involvement—assignee, requester, commenter, mentioned, approver, or task assignee. Find every ticket you're connected to without multiple filter combinations. * **Full ticket type names**: Ticket badges now show full names instead of single-letter abbreviations. "Request" instead of "R", "Task" instead of "T", making ticket types immediately clear. **Find workflows with semantic search** Search for workflows by intent, not just keywords. Serval understands what you're trying to accomplish and surfaces relevant workflows even if your search terms don't match exactly. Search results now rank by semantic relevance. *For example, search "notify manager" and find workflows about "supervisor alerts" or "leadership notifications."* # February 12, 2026 Source: https://docs.serval.com/sections/release-notes/Feb-12-2026 This release includes white-label Slack bot customization, redesigned SLAs with business hours and pause conditions, agent-powered run debugging, criteria-based assignment rules, queued workflow builder messages, and new installable workflows. ## **Highlights** * [White-Label Your Slack Bot](#white-label-your-slack-bot) * [Track Resolution Commitments with Redesigned SLAs](#track-resolution-commitments-with-redesigned-slas) * [Debug Workflows with Agent-Powered Run Inspection](#debug-workflows-with-agent-powered-run-inspection) * [Route Tickets with Criteria-Based Assignment Rules](#route-tickets-with-criteria-based-assignment-rules) * [Queue Messages in the Workflow Builder](#queue-messages-in-the-workflow-builder) * [Trigger Workflows from External Ticket Escalations](#trigger-workflows-from-external-ticket-escalations) ### **White-Label Your Slack Bot** Fully customize your Serval Slack integration to match your brand. Update the bot's appearance and behavior: * **Icon**: Upload a custom avatar for your help desk bot * **Name**: Rename the bot to match your internal branding (e.g., "IT Help" or "TechSupport") * **Permissions**: Control which Slack permissions the bot requests * **Help desk connection**: Configure how the bot connects to your help desk agent This is the central connection point between Slack and your help desk agent, completely control the experience your users see. ### **Track Resolution Commitments with Redesigned SLAs** SLA policies are redesigned with more control over how resolution targets are tracked. Set target durations per policy, choose between calendar time (24/7) or business hours tracking, and define auto-attach criteria so policies apply automatically based on priority, status, labels, or groups. * **Business hours scheduling**: Attach a working schedule to any SLA so the clock only runs during your team's operating hours * **Pause conditions**: Stop the SLA timer when tickets are waiting on a requester, vendor, or on hold, so your team isn't penalized for external delays * **At-risk visibility**: Tickets surface as on track, at risk, or breached, with SLA filters in the ticket list and performance charts in analytics ### **Debug Workflows with Agent-Powered Run Inspection** The workflow builder agent can search the 10 most recent runs of any workflow, identify failures, and pull detailed task-level information including inputs, outputs, and status. Ask the builder about recent failures and it finds the issue and surfaces the exact output of the failing task. Learn more in the [Debugging Workflows documentation](/sections/documentation/workflows/Run/debugging). ### **Route Tickets with Criteria-Based Assignment Rules** Assignment rules are redesigned around flexible, criteria-based policies. Define ticket categories in team settings, then use those categories as criteria in your assignment rules to route tickets to the right person. Combine categories with priority, labels, and other ticket properties to build precise routing logic. Each property influences assignment independently, so changing your category structure does not break your existing rules. Learn more in the [Assignment documentation](/sections/documentation/ticketing/ticket-configuration/assignment). ### **Queue Messages in the Workflow Builder** Send follow-up instructions to the workflow builder agent while it's still processing. Messages queue in order and execute sequentially. Click to interrupt the current generation and send your new message immediately. If the agent finishes before reaching queued messages, they still get handled automatically. ### **Trigger Workflows from External Ticket Escalations** When a ticket is escalated in ServiceNow or Freshservice, a webhook fires that triggers a Serval workflow automatically. Submit or escalate tickets in your external ITSM and Serval runs the automation. Works for both service requests and incidents, so your Serval workflows stay connected to tickets regardless of where they originate. Learn more in the [ticket syncing documentation](/sections/documentation/ticketing/ticket-configuration/syncing). ## **Integrations** **Freshservice Webhooks** Real-time syncing with Freshservice via webhooks. Receive live updates from Freshservice to keep tickets, statuses, and field changes synchronized across both platforms. ## **Installable Workflows** **20 New ServiceNow Workflows** Pre-built workflows covering incidents, problems, and change requests. Create, update, and resolve records including approvals and status transitions. **11 New Workday Workflows** Pre-built workflows for common Workday operations. Automate employee data tasks and HR processes with ready-to-install templates. ## **Workflows** **Restrict Workflows by Access Profile** Associate specific workflows with Access Profiles to control which automations run at the profile level. Map permissions from external systems like ServiceNow to the workflows Serval ingests. ## **Ticketing** **Group Tasks Under Parent Tickets** Toggle task grouping in the ticket list view to display tasks nested under their parent tickets in a tree structure. Save grouped views as custom views to keep tasks organized instead of buried in flat lists. ## **UI Improvements** **Status Group Management Redesign** Redesigned status group interface with a cleaner editing and management experience. **Sticky Ticket Conversation Headers** Long ticket names display fully without truncation. The header and activity tabs stay fixed when scrolling through long conversations. **Rich Access Request Updates in Slack** Access requests push detailed status updates to Slack threads. See approval steps, pending approvers, and provisioning status in real time with emoji indicators. Multi-step approvals display each step with comma-separated approvers. **Permission-Aware Navigation** Front-end and back-end permissions stay synchronized to prevent errors when navigating restricted pages. Non-admins redirect to the first team page they have access to. Admins see an explanation with a link to self-grant access and join the team. **Auto-Close Team Switcher** The team switcher dropdown closes immediately after selecting a new team in both collapsed and expanded sidebar modes. # February 26, 2026 Source: https://docs.serval.com/sections/release-notes/Feb-26-2026 This release includes child workflow composition, Slack reaction triggers, workflow-backed catalog items, access revocation via API and workflows, default access profiles and app owners, a new ticket analytics dashboard, and more. ## **Highlights** * [Ingest and Trigger Third-Party Ticketing Catalog Items](#ingest-third-party-ticketing-catalog-items) * [Build and Approve Child Workflows](#build-and-approve-child-workflows) * [Trigger Workflows from Slack Reactions](#trigger-workflows-from-slack-reactions) * [Revoke Access via API and Workflows](#revoke-access-via-api-and-workflows) * [Configure Default Access Profiles and App Owners](#configure-default-access-profiles-and-app-owners) ### **Ingest Third-Party Ticketing Catalog Items** You can now ingest third-party ticketing catalog items and configure them to run as workflow-backed actions. Define the workflow once, expose it as a catalog item, and control exactly how users can trigger it through your help desk and request flows. You can now: * **Ingest catalog items from existing workflows**: Publish repeatable workflow automations as requestable catalog actions instead of rebuilding logic. * **Configure trigger behavior**: Choose how catalog items are launched, including request-time inputs and trigger pathways that fit your team’s intake model. * **Run catalog actions as workflows**: Every catalog item execution maps to a workflow run, so approvals, audit history, and operational logic stay centralized in one system. *For example, publish an "Onboard Contractor" catalog item that collects requester inputs, triggers your onboarding workflow, and tracks every step in workflow run history.* ### **Build and Approve Child Workflows** Child workflows are now available in Serval. Compose reusable automation building blocks and call them from parent workflows — making complex automations easier to scale across teams without duplicating logic. Use this for shared onboarding and offboarding steps, centralized approval flows, or standard escalation routines that multiple teams can run from a single source of truth. Key capabilities in this release: * **Reusable workflow modules**: Build once and call the same child workflow from any parent — keep onboarding, offboarding, and escalation logic consistent across teams. * **Smarter AI building**: The workflow builder agent understands child workflow input fields and types, so parent workflow calls are generated with the correct parameters every time. * **Approval visibility in parent context**: If a child workflow requires approval, that approval surfaces in the parent ticket and triggers a Slack notification — nothing stalls silently. Learn more in the [workflow configuration documentation](/sections/documentation/workflows/Configure/build-guide#child-workflows). ### **Trigger Workflows from Slack Reactions** Workflows can now be triggered when someone reacts to a Slack message. Use the new "message reaction added" or "message reaction removed" event triggers and specify any emoji slug as the condition. React with 👀 to assign a ticket, react with ✅ to close it — any reaction your team already uses can drive automation. *For example, build a workflow that watches for a 🔁 reaction on unresolved tickets and automatically escalates them to the on-call engineer.* Learn more in the [workflow types documentation](/sections/documentation/workflows/Configure/types#event-triggered-workflows). ### **Revoke Access via API and Workflows** Access revocation can be embedded directly into offboarding workflows as a seamless step, instead of a separate manual process. Trigger revocations through the Serval API or from within a workflow to automate deprovisioning, enforce time-limited access expiry, and keep offboarding actions consistent across systems. *For example, build a workflow that automatically revokes Okta app access when an employee's role changes in Workday — no ticket required.* ### **Configure Default Access Profiles and App Owners** **Default access profiles**: Set a default access profile for any application. When a team member is switched to that profile, entitlements automatically follow — no manual reassignment required. **App owners**: Designate owners for each connected application in the Settings tab. App owners are notified when access is requested for their app and can be added as a required approval step in access request workflows — ensuring the right stakeholder is in the loop before access is granted. *For example, make the Head of Engineering an approver for all GitHub access requests — they're automatically included in every new request workflow for that app.* ## **Access Management** **Customize Ticket Status Colors** Assign colors to ticket statuses to visually distinguish request states at a glance. Color-coded statuses make queues easier to scan, help spot bottlenecks, and keep triage conventions consistent across your team. **Access Requests in Copilot Thread** When a user opens an access request from within a copilot conversation, the request appears inline in that thread — full context on approvals, provisioning status, and access history, without switching views. **Public API for App Relationships** New CRUD endpoints for app relationships are available in the public API. Manage app owner associations and related metadata programmatically. ## **Integrations** **Daytona** Connect Daytona development environments to Serval. Build workflows that provision and manage Daytona workspaces, and automate developer environment setup as part of onboarding. **Front** Integrate Front with Serval to route conversations from Front into your help desk. Manage tickets and responses without leaving your existing Front workflow. **GitLab** Pull GitLab repository and documentation content into your Serval knowledge base. Build workflows that reference GitLab data and surface relevant files in help desk responses. **Exchange Online** Manage Exchange Online mailboxes and mail configurations from Serval workflows using PowerShell. Automate email provisioning, distribution group management, and mailbox policy enforcement. **Microsoft Teams** An updated Microsoft Teams integration with expanded capabilities. Teams Forms can now be used to collect structured input from users, and domain filtering lets you scope which users and conversations flow into your help desk. ## **Ticketing** **Routing and Assignment** * **Individual assignee targets in assignment rules**: Route tickets to specific users (not just groups) based on category, priority, or labels. * **Email multi-team routing**: Route incoming email tickets across multiple teams using address- or rule-based intake paths. **Ticket Context and Triage** * **Ticket categories on tickets**: Set and review categories directly on tickets, including categories inferred during Help Desk Agent escalation. * **Original Slack message references**: Tickets created from Slack now include a direct link back to the source message for faster context. **Ticket Intake Controls** * **Ticket creation options**: New manual ticket creation controls give teams more flexibility in how requests are submitted and initially routed. **Team Name Badge on Workflow Cards** Workflow cards in the catalog now display the owning team's name, making it easier to browse and filter automations owned by a specific team. ## **Guidance** **Guidance Tickets Tab** Guidance now includes a Tickets tab that shows which tickets each guidance item has been applied to and tracks usage over time. See exactly how your guidance is driving agent behavior and which items are most active. ## **Knowledge** * **Access controls are enforced**: ServiceNow User Criteria now applies during knowledge retrieval, so restricted articles are only shown to eligible users. * **Link-first knowledge references**: You can paste permanent knowledge URLs directly in workflow builder and help desk flows. * **Better response relevance**: The Help Desk Agent uses Slack channel context in thread replies about knowledge. * **Faster retrieval**: Knowledge filtering is now lower-latency with no expected quality tradeoff. ## **Workflows** **Jump to Builder from Run History** Workflow run history now includes an "Investigate in Builder" button. Click it to open that run directly in the workflow builder chat, pre-loaded with run context. Ask the agent why something failed and it immediately has everything it needs — no copying run IDs required. ## **Installable Workflows** **New Okta Workflows** Pre-built workflows for common Okta identity management operations. **New FleetDM Workflows** Pre-built workflows for device management operations in FleetDM. **New HubSpot Workflows** Pre-built workflows for HubSpot CRM automation. **New Ramp Workflows** Pre-built workflows for Ramp spend management automation. **Misc New Installables** Additional pre-built workflows across integrations — see the full catalog in app.serval.com for the latest additions. # February 5, 2026 Source: https://docs.serval.com/sections/release-notes/Feb-5-2026 This release includes service catalog ingestion, support tokens for customer access, new team roles, access extensions, sidebar settings improvements, and new integrations. ## **Highlights** * [Enable Support Token Access for Customer Tenants](#enable-support-token-access-for-customer-tenants) * [Ingest Service Catalogs and Run Them as Workflows](#ingest-service-catalogs-and-run-them-as-workflows) * [Assign Granular Team Roles](#assign-granular-team-roles) * [Extend Access from Any Ticket](#extend-access-from-any-ticket) * [Navigate Redesigned Sidebar and Team Settings](#navigate-redesigned-sidebar-and-team-settings) ### **Enable Time-Bound Support Token Access for Customer Tenants** Serval support engineers can now request temporary access to customer tenants via support tokens. Admins generate time-limited tokens that grant Serval CSEs the access they need to troubleshoot issues directly. Tokens expire automatically, and all access is logged for audit purposes. ### **Ingest Service Catalogs and Run Them as Workflows** Import your existing service catalog items from [ServiceNow](/sections/integrations/servicenow), [Jira Service Management](/sections/integrations/jira), and [Freshservice](/sections/integrations/freshservice) and run them as Serval workflows. Migrate your catalog without rebuilding from scratch—Serval ingests catalog items and converts them into executable workflows that your team can trigger, customize, and extend. *For example, import your "New Laptop Request" catalog item from ServiceNow and immediately run it as a Serval workflow with all the original fields and approval logic intact.* ### **Assign Granular Team Roles** Three new roles provide finer control over team permissions: * **Viewer**: Read-only access to tickets, workflows, and team content * **Limited Builder**: Create and edit workflows without publishing or managing team settings * **Builder**: Full workflow creation and publishing rights without admin-level team management Assign the right level of access to each team member based on their responsibilities. ### **Extend Access from Any Ticket** Users can request additional time for expiring access from any ticket—either the original access request or a new one. When time-limited access needs to be extended, request an extension and get the access duration updated directly. *For example, a contractor with 30-day AWS access can request a 2-week extension from their original access ticket without creating a new request.* ### **Navigate Redesigned Sidebar and Team Settings** The sidebar and team settings have been redesigned for faster navigation and easier configuration. * **Team search**: Find teams instantly by searching in the sidebar instead of scrolling through a list * **Focused team view**: View one full team at a time for a cleaner experience * **Direct settings access**: Click Settings to view all team configuration options—no more hunting through the "..." menu * **Capabilities toggle**: Enable or disable specific Serval products per team from the new Capabilities tab in Settings ## **Integrations** **Box** Connect Box to pull documents into your knowledge base. Build workflows that read files, sync folders, and use Box content as context for help desk responses. **Justworks** HR platform integration for automating employee data workflows. Sync reference files, automate onboarding documentation, and build HR automations with Justworks data. **Azure Resource Manager** Manage Azure cloud resources directly from Serval workflows. Query resource groups, manage deployments, and automate cloud infrastructure tasks. **Snowflake** Connect Snowflake data warehouses to Serval. Query data, manage users, and build workflows that interact with your Snowflake environment. ## **Ticketing** **Manually Escalate Tickets from Slack** Escalate tickets to a human agent directly from Slack without AI involvement. Click the manual escalation button to immediately route the ticket to your team queue—no LLM processing required. **Toggle Off Email Auto-Responses** Disable automatic email responses per team. When turned off, Serval creates tickets from incoming emails without sending an immediate acknowledgment. Useful for teams that prefer manual first responses. **Send Private Messages with the Lock Emoji** Add a 🔒 lock emoji to your message in a team-only help desk channel to make it a private internal note on that ticket. The message stays visible only to team members and won't be shared with the ticket requester. Quick way to add internal context without leaving Slack. ## **UI Improvements** **Suggested Team Members** Team settings now suggest users to add based on ticket interactions and organizational data. Improve team coverage by quickly adding members who frequently interact with your team's tickets. **Assignment Rules Interface Updates** Refreshed assignment rules configuration with clearer controls and improved visual feedback. Easier to create and manage rules that automatically route tickets to the right assignees. # January 15, 2026 Source: https://docs.serval.com/sections/release-notes/Jan-15-2026 This release includes org admin joining new teams from ticket links, view assignment reason on hover, launching workflows from application tabs, new UI changes and integrations. ## **Highlights** * [Org Admin Join Teams Instantly from Ticket Links](#org-admin-join-teams-instantlyl-from-ticket-links) * [View Assignment Reasons on Hover](#view-assignment-reasons-on-hover) * [Launch Workflows Directly from Application Tabs](#launch-workflows-directly-from-application-tabs) * [Search New Applications in Redesigned Layout](#search-applications-in-redesigned-layout) ### **Org Admin Join Teams Instantly from Ticket Links** Organization admins can add themselves to Serval teams immediately when clicking a ticket link, without having to navigate to org settings first. If the ticket belongs to a team you're not a member of, but you are a Serval admin, approve your own access and view the ticket in the ticket link. ### **View Assignment Reasons on Hover** Understand why tickets are assigned to specific people. Hover over an assignee to see the reasoning behind the assignment, whether it's based on workload balancing, expertise matching, or manual selection. Clearer context helps teams manage handoffs and workload distribution. ### **Launch Workflows Directly from Application Tabs** Create workflows without leaving the application context. Click the new workflow button directly from the Workflows tab within any connected application. Build automations specific to that service while viewing its available actions and configurations. ### **Search New Applications in Redesigned Layout** Find applications faster with the new searchable layout. Filter by name to locate integrations quickly instead of scrolling through lists. The updated design surfaces applications more efficiently for teams managing multiple connected services. ## **Integrations** **AWS Organizations** Retrieve your AWS organizational structure directly in Serval. Access accounts, organizational units, and their relationships to build workflows that understand your cloud environment hierarchy. **Freshservice User Mentions and Attachments** Bi-directional support for user mentions and file attachments in Freshservice tickets. Tag colleagues and share files from either platform with automatic synchronization. Comments with mentions and attachments flow between Serval and Freshservice seamlessly. **Filter Jira Priorities by Request Type** Scope Jira priority options based on request type. When creating or updating Jira issues through workflows, only relevant priorities appear based on the selected request type. Reduces confusion and ensures teams use the correct priority levels. **Streamlined Teams Configuration** Configure Microsoft Graph and Teams integrations with a single sign-in flow. Offers quicker Teams setup with more to come ## **UI Improvements** **Compact Ticket Header Layout** Ticket headers display essential information in a denser format. See ticket ID, status, priority, and assignee at a glance with reduced vertical space. More room for conversation content on smaller screens. **Improved Copy-to-Clipboard Interactions** Copy actions for IDs, emails, and API keys provide immediate visual feedback. Clear confirmation indicators show when content is copied successfully. Faster, more reliable clipboard interactions across the application. # January 21, 2026 Source: https://docs.serval.com/sections/release-notes/Jan-21-2026 This release includes knowledge source permission enforcement, a redesigned ticket experience with archiving and feedback collection, enhanced keyboard navigation with command palette, Slack ticket status updates, and file support for workflow inputs and outputs. ## **Highlights** * [Respect Knowledge Source Permissions](#respect-knowledge-source-permissions) * [Navigate the Redesigned Ticket Experience](#navigate-the-redesigned-ticket-experience) * [Archive Tickets to Declutter Active Queues](#archive-tickets-to-declutter-active-queues) * [Collect Ticket Feedback](#collect-ticket-feedback) * [Navigate Faster with Keyboard Commands](#navigate-faster-with-keyboard-commands) * [View Ticket Status in Slack](#view-ticket-status-in-slack) * [Use Files as Workflow Inputs and Outputs](#use-files-as-workflow-inputs-and-outputs) ### **Respect Knowledge Source Permissions** The help desk agent now respects document permissions from your connected knowledge sources. Users only see answers from documents they have permission to access in Confluence, SharePoint, Google Drive, and other connected sources. Security boundaries are maintained automatically without manual configuration. ### **Navigate the Redesigned Ticket Experience** Experience a cleaner, more focused ticket interface with better organization. * **Compact header**: Essential ticket info takes up less vertical space * **Quick contact**: Copy email addresses directly from assignee and requester chips * **Updated cards**: Workflow execution and access request cards display refreshed styling with clearer status indicators about workflow and access progress ### **Archive Tickets to Declutter Active Queues** Team managers can archive resolved tickets to keep active views clean. Archived tickets disappear from team ticket lists, "My Tickets", and analytics dashboards but remain accessible in read-only mode. Access archived tickets anytime from the team menu under "Archive" to maintain audit trails without cluttering daily workflows. ### **Collect Ticket Feedback** The ticket feedback system has been overhauled for more robust collection and processing. Feedback on resolution can now be tracked via "like/dislike" and "rating on a scale of 1-5" with comments. Adjust the collection frequency and who will request feedback through the feedback portal in each team. This is team-specific feedback. ### **Navigate Faster with Keyboard Commands** New keyboard shortcuts make navigating Serval faster and more efficient. * **Command palette** (`CMD+K` / `Ctrl+K`): Search across tickets, workflows, users, apps, guidance, and knowledge articles. Type a ticket ID to jump directly to it, or search by title or content to surface relevant results. * **Keyboard shortcuts reference** (`CMD+/`): View all available keyboard commands organized by context (Global, Ticket Details, Workflow Builder, and more). * **Copy ticket link**: Quickly copy a direct link to any ticket from the actions menu for sharing with team members. Click the three dots at the top of the ticket and click "Copy link" from the dropdown. ### **View Ticket Status in Slack** Updated Slack status UI so you can dynamically view ticket and workflow progress in the Slack message. Users clearly see what type of automation is being run to help execute their request, driving clarity to users and admins. ### **Use Files as Workflow Inputs and Outputs** Workflows can now accept files as inputs and return files as outputs. Build automations that process documents, generate reports, and move files between systems. * **Inputs**: Upload a receipt to Ramp for expense processing, submit a SOC-2 report to Vanta for compliance tracking, or send documents to Google Drive for storage * **Outputs**: Export data as a CSV, generate a text file of your Serval audit logs, or create reports from workflow data ## **Workflows** **Workflows are now more powerful and reliable.** * **Long-running support**: Workflows can run for hours or days without timing out. This allows for long-running workflows like migrating catalogue items from another ITSM to Serval. * **Speed**: Faster and more reliable workflow progress tracking and cancellation ## **Integrations** **HiBob** HR platform for managing employee lifecycle, time off, and workforce planning. Connect using Service User authentication to sync employee data and automate HR workflows like onboarding provisioning and time-off synchronization. **SharePoint** Access SharePoint sites, document libraries, and files for knowledge base integration. Build document-centric workflows that read from and write to SharePoint. **Okta Webhooks** Trigger workflows automatically when user lifecycle events occur in Okta. Receive real-time notifications for user creation, updates, deactivation, and group membership changes. **Granular Microsoft Permissions** Choose exactly which Microsoft Graph permissions Serval can access. Select from preset bundles (Teams, OneDrive/SharePoint, Mail/Calendar, Licenses, Groups) or pick specific permissions for maximum control and security compliance. ## **Installable Workflows** **Assign to Me** One-click installable workflow for IT agents to quickly claim ticket ownership. Add from the workflow library to enable fast self-assignment. ## **Ticketing** **Automate Email CC Handling** Ticket subscribers are automatically CC'd on all outbound emails. When someone replies via CC on an email thread, they're automatically added as a ticket subscriber. Keep stakeholders informed without manual forwarding. **Add Checklists to Rich Text Fields** Insert checkboxes and formatted lists into any rich text field across the platform. Track task completion directly in ticket descriptions, custom fields, and workflow forms. **Create Standard Tickets for Testing** Team members can create normal help desk tickets instead of internal execution tickets. Test workflows and agent behavior with production-like ticket routing and responses. ## **Guidance** **Add Hyperlinks in Guidance** Insert clickable links within guidance documents to reference external documentation, internal wikis, tools, or related guidance pages. Select text and click the add link button, or select text and paste a URL directly with `CMD+V`. ## **API Updates** **Entitlements Renamed to Roles** Public API and workflow builder now use "Roles" instead of "Entitlements" for consistency. Update integrations that reference entitlement endpoints. **Standardized API Pagination** All public API endpoints follow Google AIP-158 pagination standards. Consistent page tokens and response formats across every list endpoint for a predictable developer experience. # January 9, 2026 Source: https://docs.serval.com/sections/release-notes/Jan-8-2026 This release introduces guidance diff view for reviewing AI suggestions, ticket transfers via @Serval, installable workflow browsing, a redesigned access catalog, and natural language workflow approvals. ## **Highlights** * [Review Suggested Guidance Changes with Diff View](#review-suggested-guidance-changes-with-diff-view) * [Transfer Tickets to Another Team by Tagging Serval](#transfer-tickets-to-another-team-by-tagging-serval) * [Browse Installable Workflows](#browse-installable-workflows) * [Browse All Requestable Apps and Roles from One View](#browse-all-requestable-apps-and-roles-from-one-view) * [Set Workflow Approvals with Natural Language](#set-workflow-approvals-with-natural-language) ### **Review Suggested Guidance Changes with Diff View** See exactly what the AI wants to change before accepting guidance updates. The new Compare view uses color-coded diffs just like code reviews: red strikethrough for deletions, green highlighting for additions. Spot the differences instantly without switching between versions. ### **Transfer Tickets to Another Team by Tagging Serval** Move tickets between teams by mentioning @Serval directly in your message. Only members of the ticket's current team can perform transfers, preventing unauthorized routing changes and ensuring proper ownership handoffs. ### **Browse Installable Workflows** Discover and deploy pre-built automations with the dedicated workflow browser. The two-column interface organizes templates by service, separating installed apps from available ones. Search and multi-select to add multiple automations at once. ### **Browse All Requestable Apps and Roles from One View** Browse every requestable app from a single screen in the redesigned Access Catalog. Previously, you had to pick a team first and hunt through each one to find the right app. The updated navigation surfaces more details as you select roles and resources, including descriptions and approval methods, so you know what you're requesting before you submit. ### **Set Workflow Approvals with Natural Language** Describe your approval process in plain English as an alternative to using the dropdown selector. The AI agent resolves specific users via email, identifies groups through fuzzy matching, or sets up manager-based approval chains automatically. Configure approvals faster without having to click toggles. Also, tag users, app request roles, groups and approval workflows directly in workflows with the @ sign, so you can use pre-built configurations directly in workflows. ### **View Detailed Sync History for Integrations** Monitor integration health with sync history logs in application settings. Track status of recent runs (successful, failed, or running) with breakdowns of items added, updated, or removed. Troubleshoot partial failures across your connected apps. ## **Integrations** **Mosyle** Apple device management for businesses and schools. Manage users, devices, and group assignments across your Apple fleet. **Snipe-IT** IT asset tracking and inventory management. Track hardware lifecycle, manage check-ins and check-outs, and maintain audit trails for compliance. **Cisco Meraki** Cloud-managed networking infrastructure. Monitor network devices, manage configurations, and automate provisioning across distributed locations. **Oomnitza** IT asset management and lifecycle platform. Track hardware, manage software licenses, and automate asset provisioning for onboarding and offboarding. **Brex** Spend management and corporate card platform. Build workflows for expenses, budgets, and card management with built-in healthchecks. ## **Installable Workflows** **Retrieve Microsoft 365 User Information** Pre-built workflow to retrieve user profiles from Azure Active Directory (Entra ID). Fetch job titles, departments, account statuses, manager info, group memberships, and licenses with one-click installation. **Installable Workflows for Jira** Four new workflows for common Jira tasks. Create issues, retrieve issue details, transition statuses, and list projects. Customize with approval steps or input requirements to match your team's procedures. ## **Ticketing** **Personalized and Org-Wide Ticket Assignment Notifications Settings** Configure ticket assignment notifications at three levels: personal, team, or org-wide (admin only). Choose Slack or email delivery based on your preferences. Notifications include ticket title, requester details, and a direct link to your work. **Pre-Select Current Team in Ticket Modal** The system pre-selects the team you're viewing in the ticket creation dialog. Reduces manual steps and ensures contextual routing by default. ## **Other Notable Improvements** **User Identity Context in Help Desk Responses** The help desk agent can now retrieve organizational details from connected identity providers. Department, job title, and manager information from apps like Okta and Google Workspace flow into conversations automatically, improving accuracy for role-based access requests without manual lookups. **Markdown Tables in Text Editor** Use standard pipe syntax to create and view structured tables within tickets, workflow descriptions, and guidance documents. Present technical specifications, feature comparisons, and task statuses in a clear, organized format. **Custom Placeholders in Workflow Dropdowns** Add custom placeholder text to dropdown fields in the Workflow Builder. Users see contextual hints like "Choose a department" instead of the generic "Select an option" when filling out workflow confirmation forms. **Improved Magic Link Login** A dedicated confirmation button appears when accessing Serval via magic links. Clear error messages notify users when links expire and provide a path to request a new one. **Improved Code Folding in Workflow Run Details** Collapse and expand nested JSON structures in workflow run histories. Navigate input and output panels more easily. Resolved layout issues in Google Chrome. **Enhanced Visibility for Deactivated Users** Names appear with a "(Deactivated)" suffix in ticket lists, asset tables, and workflow history. Avatars display a deactivation icon with a tooltip on hover for clear context when auditing former employees. **Include Deactivated Users in Identity Lookups** Deactivated accounts are included by default when searching by user ID. Historical data and audit logs provide complete context after employee offboarding. Filter out inactive accounts when needed. **Search Recommended Access Role Imports** Filter suggested integrations with a search bar in "Recommended Import" in Applications. Search by name of integration to view potential access roles to import. **Guidance Editor Improvements** Character limits increased from 30,000 to 50,000 characters. A new "Compare" view highlights sentence-level differences with word-level precision where needed. Stale data handling prevents overwrites during concurrent edits. The help desk agent retrieves the most recent deployed version. # July 3, 2026 Source: https://docs.serval.com/sections/release-notes/Jul-03-2026 Assign tickets to groups, share workflows across teams, and let team managers override approvals from a ticket. ## Highlights * [Share workflows across teams](#share-workflows-across-teams) * [Assign tickets to groups](#assign-tickets-to-groups) * [Manager override for approvals](#manager-override-for-approvals) ### Share workflows across teams A team that owns a published workflow can now share it with other teams in your org. The borrowing teams can run it manually or through its own Help Desk Agent, while every step still executes inside the owning team's environment, against the owner's integrations and credentials. The borrowing team gets a result, but not the credentials. *For example, your HR team can run an IT-owned workflow that verifies an employee's identity through Okta before a privileged action, without HR ever touching the Okta connection.* ### Assign tickets to groups Tickets can now be assigned to groups and you also can set up assignment rules that target groups. Once a ticket is routed to a group, Serval can automatically assign it to a group member (round robin style) or leave it for human triage. With assignment groups, teams can balance workloads and manage reports and SLAs at the group level. *For example, send VPN tickets to your Network group and let Serval spread the work across group members.* See [Assignment groups](/sections/documentation/ticketing/ticket-configuration/assignment-groups) for setup. ### Manager override for approvals Team managers can now override approvals for access requests and workflow runs from a ticket. When an approver is unavailable and a request is urgent, a manager can step in and keep things moving instead of letting the ticket sit. *** ## Help desk agent **Collect feedback on the web portal** Serval now asks for feedback on tickets submitted through the web portal, just as it does on Slack and Teams, so you get a consistent picture of user satisfaction across every channel. ## Integrations **Restrict SharePoint site visibility** If your organization limits the Microsoft Graph integration to specific SharePoint sites with the `Site.Selected` scope, you can now provide the list of allowed sites directly in Serval. Serval reads just those sites, so teams only see the SharePoint content they are meant to see. # July 10, 2026 Source: https://docs.serval.com/sections/release-notes/Jul-10-2026 Improved Microsoft Teams experience: reply clarification in DMs, reply-with-quote routing, and custom avatars for the Serval bot. ## Highlights * [Reply clarification in Teams DMs](#reply-clarification-in-teams-dms) * [Reply with quote in Teams DMs](#reply-with-quote-in-teams-dms) * [Custom help desk agent avatar in Teams](#custom-help-desk-agent-avatar-in-teams) ### Reply clarification in Teams DMs Microsoft Teams DMs don't have threads, so a conversation with Serval can span several open tickets at once. When you send a message that could belong to more than one of your open tickets, Serval now sends you a card listing the most likely tickets, ranked by relevance, along with the option to start a new ticket instead. This ensures that short, ambiguous replies always land on the ticket you want. *For example, if you reply "no" while you have three open tickets, Serval asks which ticket you mean instead of guessing.* ### Reply with quote in Teams DMs You can now use Microsoft Teams' built-in **reply with quote** feature to tell Serval exactly which conversation you're responding to. Hover over any Serval message, choose reply with quote, and Serval routes your reply to that message's ticket. ### Custom help desk agent avatar in Teams If your organization customizes its help desk agent with its own name and logo, Serval's replies in Teams now show your custom avatar alongside your custom agent name. # July 17, 2026 Source: https://docs.serval.com/sections/release-notes/Jul-17-2026 Automatic ticket bumps for unresponsive requesters and version diffs for workflows and skills. ## Highlights * [Automatically bump ticket requester](#automatically-bump-ticket-requester) * [View version diffs for workflows and skills](#view-version-diffs-for-workflows-and-skills) ### Automatically bump ticket requester When a ticket is waiting on the requester, the help desk agent can now follow up automatically. Configure how long the agent waits between reminders, how many times it follows up, and the hours during which reminders can go out. If the requester still doesn't respond after the final reminder, you can have the agent close the ticket with any status in your Done or Canceled groups, along with an optional closeout message. Follow-ups aren't canned responses; the agent reads the ticket and writes a reminder that fits the conversation. Learn more in [Help Desk Agent behavior](https://docs.serval.com/sections/documentation/helpdesk/agent-behavior). ### View version diffs for workflows and skills You can now compare any two versions of a workflow or skill directly from its edit history. Select two versions and hit compare to see what changed in the title, description, and content, and for workflows, the code itself, with changed sections highlighted so you know exactly where to look. This makes it easy to review what a teammate changed or track down when a behavior shifted. # July 24, 2026 Source: https://docs.serval.com/sections/release-notes/Jul-24-2026 Create custom roles, sync ticket attachments, trigger workflows when a ticket is assigned, and submit tickets on behalf of others. ## Highlights * [Create custom team roles](#create-custom-team-roles) * [Sync attachments to connected ticketing systems](#sync-attachments-to-connected-ticketing-systems) * [Trigger workflows when a ticket is assigned](#trigger-workflows-when-a-ticket-is-assigned) * [Submit tickets on behalf of others](#submit-tickets-on-behalf-of-others) ### Create custom team roles Serval's built-in team roles cover most teams, but they move in a fixed ladder: each role includes everything the one below it can do. You can now define custom team roles instead, picking exactly the permissions a role should carry. Custom roles live alongside the built-in ones in the same role picker, so assigning them is no different from assigning Agent or Manager. *For example, you can give your security team a role that views audit logs and runs access reviews without also handing them the ability to publish workflows.* Learn more in [Custom team roles](https://docs.serval.com/sections/documentation/platform/permissions#custom-team-roles). ### Sync attachments to connected ticketing systems Files now flow both ways between Serval and your connected ticketing systems. When a requester adds an attachment on the external system, it appears in the Serval ticket thread and is available to the Help Desk Agent; when a file is added in Serval, it's uploaded to the linked external record. Attachment sync is available for ServiceNow, Jira, Freshservice, Linear, and Zendesk. Learn more in [Ticket syncing](/sections/documentation/ticketing/ticket-configuration/syncing). ### Trigger workflows when a ticket is assigned Workflows can now start from a new **Ticket assigned** event. Whenever a ticket's assignee changes, Serval can kick off a workflow, so you can automate the handoffs that happen the moment work lands with a person or group. *For example, run a workflow that posts a heads-up in a Slack channel whenever a ticket is assigned to your Network group.* See [Workflow triggers](/sections/documentation/workflows/Run/triggers) for more. ### Submit tickets on behalf of others Agents and delegates, such as executive assistants who are granted the permission, can now name a different requester when creating a ticket or update an existing ticket's requester. The named requester gets visibility and notifications, and the ticket shows who actually submitted it. *** ## User management **Okta user webhooks** Okta user changes can now reach Serval within seconds through an event hook instead of waiting for the scheduled sync. **Choose which source wins for each user field** When more than one connected source syncs the same user, you can now rank which source is authoritative for each built-in profile field, such as first name, profile photo, timezone, and deactivation status. **Match access profiles on custom user fields** Access profiles can now match users by your own custom user fields, not just built-in attributes, with a new User fields condition. **Manage and deactivate users in bulk** The Organization Settings page now separates your directory into **Users** and **Deactivated** tabs, so deactivated accounts are easy to find instead of buried among active ones. On the Users tab, admins can multi-select accounts and deactivate them in a single action. ## Help desk agent **Customize requester follow-up messages** For every automatic follow-up and the optional closeout message, you can now choose between an AI-written message and your own custom text, complete with variables for first name, last name, full name, and email. # July 31, 2026 Source: https://docs.serval.com/sections/release-notes/Jul-31-2026 Help Desk Agent evaluations in beta, native ticket status workflows, and richer ticket filters and search ## Highlights * [Help desk agent evaluations in beta](#help-desk-agent-evaluations-in-beta) * [Native ticket status workflows](#native-ticket-status-workflows) * [More ways to filter and search ticket views](#more-ways-to-filter-and-search-ticket-views) * [Org-wide channels on Slack Enterprise Grid](#org-wide-channels-on-slack-enterprise-grid) ### Help desk agent evaluations in beta Evaluations, now in beta, let you safely and systematically test how your Help desk agent handles realistic support scenarios without manually creating tickets. Each evaluation is a test case: define the requester, their opening message, the scenario background, and a successful outcome, then run it as a single reply, an automatic conversation with a simulated requester, or an interactive session you drive. Workflow calls and access requests are simulated by default, so nothing changes in your connected systems unless you explicitly allow selected workflows to run live. Every run keeps the full conversation, tool and workflow activity, and outcome on revisioned configs. To try it, head to Settings, then Evaluations, or just ask Catalyst to run an evaluation. *For example, simulate a new hire asking for access to Figma and verify the agent gathers the right context and routes the request for approval, without touching your real systems.* Learn more in [Evaluations](/sections/documentation/helpdesk/evaluations). ### Native ticket status workflows You can now define a native, editable status-transition workflow for each ticket type, allowing you to control which status a ticket is allowed to move to next. Build the transitions by hand, or import them straight from an existing Jira workflow so your Serval ticket lifecycle matches the one your team already runs in Jira. Once transitions are enabled for a ticket type, both human agents and the Help Desk AI Agent are held to the paths you define. *For example, restrict an Incident so it can only move Open → In Progress → Resolved* Learn more in [Ticket statuses](/sections/documentation/ticketing/ticket-configuration/statuses). ### More ways to filter and search ticket views Ticket views gain several new ways to slice your queue. You can now filter by assignment group with an **is not** condition, by whether a ticket has been escalated, by its source, and by the connected service it syncs with. Views can also match on requester attributes (any custom user field) and you can search your tickets by the external ticket ID or key from the connected system. *For example, build a view of every escalated ticket that did not come from your Network group, or paste a Jira key like `INC-482` into search to jump straight to the linked Serval ticket.* See [Filter and sort tickets](/sections/documentation/ticketing/manage-collaborate/filter-sort) for more. ### Org-wide channels on Slack Enterprise Grid Serval now supports org-wide channels on Slack Enterprise Grid. Teams on Enterprise Grid can connect channels that span the whole Slack organization, so the Help Desk Agent works in shared channels that aren't scoped to a single workspace. *For example, connect a company-wide `#it-help` channel that lives at the Enterprise Grid level and route its requests into Serval like any other Slack channel.* See the [Slack integration](/sections/integrations/slack) for setup. *** ## Ticketing **Major incident resolution cascades to linked tickets** Resolving a major incident now propagates that resolution to the tickets linked to it, so the whole cluster closes out together instead of one at a time. **Single user as a secondary fallback assignee** Fallback assignment can now name an individual user, not just a group, as the secondary fallback for a team's tickets. **Label conditions on assignment routing rules** Assignment routing rules can now branch on a ticket's labels, so you can route by label as well as by the existing conditions. See [Assignment routing](/sections/documentation/ticketing/manage-collaborate/assignment-routing). **Hide custom fields by default** A custom field can now be marked hidden by default, so it stays out of the way until someone chooses to reveal it. See [Custom fields](/sections/documentation/ticketing/ticket-configuration/custom-fields). **Notify assignees about internal notes** Ticket assignees are now notified when an internal note is added, so private context doesn't slip past the people working the ticket. ## Knowledge **Requester-facing knowledge catalog** Requesters can now browse a knowledge catalog in the portal to find answers themselves, and admins can control whether the catalog card is shown. **Pause, resume, or cancel a running knowledge sync** From the connected source card you can now pause a Knowledge sync in progress, resume it later, or cancel the in-flight run entirely. This way, a long-running or misconfigured sync doesn't have to finish before you can fix it. ## Integrations **New native integrations** Serval adds four new integrations: [Paycom](/sections/integrations/paycom), [Duo Security](/sections/integrations/duo), [SAP Concur](/sections/integrations/sap-concur), and [SAP SuccessFactors](/sections/integrations/sap-successfactors). **LDAP / Active Directory is now GA** The LDAP/AD connector is now generally available and appears in the standard integrations gallery. See [LDAP / Active Directory](/sections/integrations/ldap-ad). **Set the ServiceNow knowledge portal by pasting an article link** When configuring ServiceNow knowledge ingestion, you can now set the knowledge portal simply by pasting a link to one of its articles, and the article portal path is configurable per tenant. See [ServiceNow](/sections/integrations/servicenow). **Leave AI-owned Jira tickets unassigned on escalation** For Jira ticket sync, you can now choose to leave AI-owned tickets unassigned when they escalate, instead of forcing an assignee. **Health alerts for integrations** You can now turn on health alerts for a connected app instance. Serval then runs daily health checks and flags a failing sync or check, so a broken integration surfaces instead of silently going stale. ## Users and notifications **Reactivate deactivated users** Admins can now reactivate a previously deactivated user to unblock their email and access again. **More languages** Serval now fully supports Spanish (Mexico), Korean, and Simplified and Traditional Chinese, and `locale` is now a standard, sync-able user attribute so each person's language can flow in from your connected source. **Access-review notifications on Slack, Teams, and email** User access reviews now notify reviewers where they already work: Slack, Microsoft Teams, and email. See [User Access Reviews](/sections/access-management/access-reviews). **New email notifications** Serval now supports email notifications for four more events: ticket created, access expiring soon, suggestion created, and workbench status changes. **Override OAuth endpoints on OIDC providers** Admins configuring an OIDC identity provider can now set the OAuth endpoints manually, for providers whose discovery document doesn't match the endpoints Serval should call. ## Databases **Archive and delete items** You can now archive an item to take it out of active views, and permanently delete it when it's no longer needed, with a Delete action available right from the item's detail header. **Manage schemas inside the database** Database schema management now lives in the database itself. Rename and describe a database, and share it on a per-database basis. ## Approvals & workflows **Notified approvers vs. backup approvers** Approval requests now clearly distinguish the approvers who are notified from the backup approvers who can step in, so it's obvious who's on the hook at each step. **Filter workflow run history by status and date** The workflow run history can now be filtered by run status and date range. See [Run history](/sections/documentation/workflows/Run/run-history). # June 5, 2026 Source: https://docs.serval.com/sections/release-notes/Jun-05-2026 Analytics dashboards are now in public beta, tickets now support time to first human response SLAs, and organizations can opt for EU data residency. ## Highlights * [Custom analytics dashboards (beta)](#custom-analytics-dashboards-beta) * [Time to first human response SLAs](#time-to-first-human-response-slas) * [EU data residency](#eu-data-residency) ### Custom analytics dashboards (beta) Analytics dashboards are now available in beta under **Organization → Analytics → Dashboards**. Build dashboards from any data your team's workflows surface, including Serval ticket history, applications connected to Serval, and public APIs, and assemble them from charts, tables, single-number KPIs, and text. You can create and edit dashboards manually or with natural language prompts via Catalyst (recommended). To learn more, refer to the [Catalyst documentation](/sections/documentation/catalyst/dashboards). *For example, an IT team could build a help desk health dashboard to track open ticket volume by category, status mix, SLA compliance over time, and top requesters all in one place.* ### Time to first human response SLAs Tickets now support time to first human response SLAs. You can configure the clock to start upon ticket creation or when the SLA is attached, which can be criteria-based. You can configure workflows to trigger at any point in the SLA lifecycle: before breach, at breach, or after. To learn more, refer to our [documentation](https://docs.serval.com/sections/documentation/ticketing/ticket-configuration/slas#understanding-slas). *For example, an IT team that commits to a four-hour first response after a ticket has been escalated to a human can easily enforce that SLA and automatically escalate to a manager when a ticket is approaching breach.* ### EU data residency Organizations can choose EU data residency when deploying Serval. EU-region organizations are hosted at [app.eu1.serval.com](https://app.eu1.serval.com/) on AWS EU Central, and all customer data (including tickets, knowledge base content, users, files, workflows, and audit logs) is stored and processed within the EU. To learn more, refer to our [documentation](/sections/documentation/platform/data-residency). Because the region is set at organization creation and cannot be changed afterward, EU customers should start their pilot directly in the EU region rather than the US region. *** ## Workflows and skills **Organize skills into folders** Like workflows, skills can now be organized into folders. Create folders by team, use case, or product area to keep your workspace clean as your automation footprint grows. **Bulk actions for skills and workflows** Skills and workflows now support bulk actions: move, duplicate, or delete multiple items at once. *** ## Help desk agent **Collect access requests with a form** When enabled, the help desk agent presents a form for end users to input request details such as access duration and business justification instead of gathering the details over chat. **Two-column layout for Serval Slack DMs** Serval DM messages in Slack now use a two-column layout. Fields like name, description, and ticket link render side by side rather than stacked, making it faster to scan structured information. *** ## Databases **Files as a column type** Database entries now support file attachments as a native column type. Add a Files column to any database to store documents, screenshots, or reference materials alongside the record they belong to. **Organize fields into tabs** Fields in a database entry can now be organized into tabs. Group related fields together to reduce visual clutter on entries with many attributes. # June 12, 2026 Source: https://docs.serval.com/sections/release-notes/Jun-12-2026 Serval now supports ITIL-aligned change management, ticket visibility groups enable access-controlled ticket routing for help desk teams, and the Applications page is now Integrations and Access Management. ## Highlights * [Change management](#change-management) * [Ticket visibility groups](#ticket-visibility-groups) * [Integrations and Access Management pages](#integrations-and-access-management-pages) ### Change management Serval now supports change management: a dedicated ticket type for tracking, auditing, and governing changes to your internal systems, configurations, and/or physical assets. Change tickets follow a structured lifecycle from submission through implementation, with configurable approvals, automations, and transition conditions at every stage. Three ITIL-aligned change models are available out of the box: Normal, Standard, and Emergency. You can also build a custom model by describing your change process in natural language and letting Catalyst (beta) configure it, or by setting it up manually in Team Settings. Each change model supports its own custom fields, per-status automations, and transition rules, including auto-advancement when conditions are met. Change tickets also track which assets and configuration items are affected, giving your team a clear picture of impact. *For example, an IT team rolling out a new software deployment could open a Normal Change ticket, attach the affected servers as configuration items, route it through CAB approval, and have Serval automatically notify stakeholders and trigger a post-implementation review workflow once the change is marked complete.* To learn more, refer to our [documentation](https://docs.serval.com/sections/documentation/ticketing/change-management). ### Ticket visibility groups Help desk teams can now organize tickets into visibility groups with configurable access controls. Tickets can be routed to visibility groups automatically based on filter rules, added manually by an agent, or fall into a team-wide default group. Only group members can see the tickets inside, so sensitive tickets (HR issues, security reports, executive requests) are visible only to the right subset of agents. People directly involved in a ticket (the requester, assignee, subscribers, or anyone @-mentioned) always retain access regardless of visibility group membership. *For example, a security team could create a "Security Incidents" visibility group restricted to their response team, ensuring sensitive reports are never visible to the broader help desk.* ### Integrations and Access Management pages The new [Integrations](https://docs.serval.com/sections/integrations/overview) and [Access Management](https://docs.serval.com/sections/access-management/overview) pages are replacing the previous Applications page. * The Access Management page is a dedicated surface for managing access policies and profiles across your apps. * The Integrations page is where you browse the catalog, connect new apps, and manage every connected integration. This is a UI-only change and doesn't affect any underlying functionality. *For example, an IT admin connecting a new app and an IGA admin tuning an access policy now each land on specific pages built for their job, instead of sharing a single Applications view.* *** ## Analytics **Dashboard mentions** Dashboards can now be @-mentioned in tickets and conversations, making it easy to reference the right dashboard directly in context. *** ## Integrations **Slack group sync** Slack groups are now synced as entities in Serval and can be tagged directly on tickets. Reference a Slack group anywhere you would tag a user or team to route, notify, or track work against a group of people. # June 19, 2026 Source: https://docs.serval.com/sections/release-notes/Jun-19-2026 Manage your tags from a single catalog and set owners for teams, resources, and roles. ## Highlights * [Unified catalog for tags](#unified-catalog-for-tags) * [Team, resource, and role owners](#team-resource-and-role-owners) ### Unified catalog for tags You can now apply tags to apps, skills, workflows, resources, and roles. Additionally, you can manage all tags from a single catalog in Team settings. *For example, you can tag every finance-related app, resource, and role as "finance" and pull them all up together when you are reviewing access.* ### Team, resource, and role owners In addition to apps, you can now set owners for teams, resources, and roles. Owners can now also be designated approvers in access policies, so the people who own something are the ones who approve access to it. *For example, you can make the finance systems team the owner of your finance resources and designate them as the approvers for associated access requests.* # June 26, 2026 Source: https://docs.serval.com/sections/release-notes/Jun-26-2026 Serval now has a native knowledge base in beta, and campaigns can be triggered directly from a workflow. ## Highlights * [Native knowledge base (beta)](#native-knowledge-base-beta) * [Trigger campaigns from a workflow](#trigger-campaigns-from-a-workflow) ### Native knowledge base (beta) Serval now has its own native knowledge base, available in beta. Write and organize content in a full Notion-like block editor, group articles into bases, folders, and pages, and keep a version history as you publish updates. The help desk agent searches your knowledge documents when answering questions, and you can gate visibility by access profiles so users see only what they should. Articles support rich content including images, and you can @-mention users directly in a page. ### Trigger campaigns from a workflow Campaigns can now be triggered by a workflow. Set a campaign's schedule type to "Triggered," and a workflow can kick it off, with the workflow itself firing from, webhook, a Serval event, or a cron schedule. You can also define custom `Trigger.*` template variables that the workflow passes into the campaign, so each run can be personalized with data from the triggering event. To learn more, refer to our [documentation](https://docs.serval.com/sections/documentation/campaigns/scheduling#triggered). # March 12, 2026 Source: https://docs.serval.com/sections/release-notes/Mar-12-2026 This release includes approval delegation, access requests via the CLI, lexical and keyword search for the knowledge base, new Salesforce, SailPoint, and LaunchDarkly integrations, and more. ## **Highlights** * [Approval Delegation](#approval-delegation) * [Access Requests via the CLI](#access-requests-via-the-cli) * [Lexical and Keyword Search in the Knowledge Base](#lexical-and-keyword-search-in-the-knowledge-base) * [Salesforce Integration](#salesforce-integration) * [SailPoint Integration](#sailpoint-integration) * [LaunchDarkly Integration](#launchdarkly-integration) ### **Approval Delegation** Approvers can now delegate their approval authority to another user. When an approver is unavailable, access requests and workflow approvals route to their designated delegate automatically instead of stalling. * **Set delegation rules in settings**: Admins can configure delegation per user or per group from the org settings panel. * **Clear attribution in the timeline**: The approval timeline shows who delegated and who made the final decision, so the audit trail stays clean. * **Public API support**: Delegation rules are configurable via the Serval public API for teams managing approval workflows programmatically. *For example, configure a VP of Engineering to delegate all access approvals to their chief of staff during an offsite, so GitHub requests still resolve in hours instead of days.* Learn more in the [approvals documentation](/sections/documentation/workflows/Configure/approvals#delegation). ### **Access Requests via the CLI** You can now submit and manage access requests directly from the Serval CLI. Request access, check status, and respond to approval prompts without opening a browser. This is useful for engineers and IT admins who want to handle routine access workflows without context-switching out of the terminal. ### **Lexical and Keyword Search in the Knowledge Base** The knowledge base now supports lexical and keyword search alongside semantic search. When a user asks about something by exact name, such as a specific policy title, internal tool name, or process code, results now match on the literal term rather than relying solely on meaning-based retrieval. This reduces cases where semantic search returns topically related but technically wrong results for exact-match queries. Both modes now run together, so the best result wins regardless of whether the query is conceptual or specific. ### **Salesforce Integration** Connect Salesforce to Serval to build workflows that read from and write to Salesforce records. Use it to automate IT provisioning tied to CRM data, route requests based on account or opportunity context, or surface relevant Salesforce data in help desk tickets. ### **SailPoint Integration** Connect SailPoint to Serval to incorporate your identity governance data into access workflows. Query entitlements, sync identity data, and build access request and provisioning flows that reflect your SailPoint identity model. ### **LaunchDarkly Integration** Connect LaunchDarkly to Serval to manage feature flag access through workflows. IT teams supporting engineering can handle LaunchDarkly access requests, onboard engineers to the right flag environments, and automate flag permissions as part of broader provisioning flows. *** ## **Access Management** **Restrict Users to One Role Per Application** A new toggle lets admins enforce a single active role per application for each user. When enabled, assigning a new role for an app automatically removes any conflicting roles. Use this for tools where role overlap creates access ambiguity, such as Figma, where a user should hold either Editor, Admin, or Viewer, but not multiple at once. **Public API for Access Profiles** Access profiles are now available via the Serval public API. Read and manage access profile definitions programmatically for reporting, automation, or integration with external identity tools. **Entitlement Expiration Reminders** Users now receive a notification one hour before a time-limited role expires. This gives them time to request an extension before access is automatically revoked, reducing helpdesk interruptions from unexpected access loss. *** ## **Installables** **Zoom Installable Workflows** New installable workflows for Zoom covering common IT help desk operations, including license provisioning, room management, and user account updates. Install directly from the workflow catalog. **Installable Workflows for Slack Reactions** Two new installable workflows trigger from Slack reactions. React with 👀 to assign a ticket, or ✅ to resolve it. Install from the catalog and customize to fit your team's reaction conventions. *** ## **Email** **Email Thread History on CC'd Tickets** When Serval receives an email that CC's the intake address on an existing thread, it now correctly extracts and includes quoted email history from the HTML body. Agents and teammates see the full conversation on the ticket, not just the latest message. **Routing for Emails with Failed DKIM Verification** When `allow_all_domains` is enabled and an incoming email fails DKIM verification, the ticket is now escalated to a human agent instead of being silently dropped. This addresses a gap for organizations where users forward email to the intake address via a Google Group or similar relay that breaks DKIM. *** ## **Workflows** **Workflow Builder Draft Persistence** The workflow builder now preserves your chat draft when you switch between the builder tab and run history. You can review a recent run and return to your draft exactly where you left off. *** ## **Platform** **CLI Auth Fix for Multi-Org Users** Fixed an issue where the CLI login flow would fail or behave unexpectedly for users belonging to multiple Serval organizations. Session metadata is now correctly recorded during device authentication. **Slack Reaction Workflows Now Ignore Bot Messages** Slack reaction workflows no longer trigger when a bot adds a reaction to a message. Only human reactions now fire reaction-based workflow triggers. **Approval Timestamp Clarity** The ticket timeline now shows two distinct timestamps for approvals: when the approval window opened and when the actual approval decision was made. Previously these were displayed as a single timestamp, which made it harder to audit how long approvals were pending. # March 26, 2026 Source: https://docs.serval.com/sections/release-notes/Mar-26-2026 This release includes campaigns with workflow responses, a Serval Inbox where you receive notifications in one place, web search for the Help Desk Agent, user MCP, assignment schedules, and delegating approvals and ticket assignments to a user or group. ## **Highlights** * [Send Campaigns and Collect Responses with Workflows](#send-campaigns-and-collect-responses-with-workflows) * [Receive Notifications in Your Serval Inbox](#receive-notifications-in-your-serval-inbox) * [Enable Web Search for the Help Desk Agent](#enable-web-search-for-the-help-desk-agent) * [Connect AI Assistants with User MCP](#connect-ai-assistants-with-user-mcp) * [Route Tickets Using Schedules in Assignment Rules](#route-tickets-using-schedules-in-assignment-rules) * [Delegate Approvals and Ticket Assignments](#delegate-approvals-and-ticket-assignments) ### **Send Campaigns and Collect Responses with Workflows** Broadcast templated messages and collect replies through attached **workflows**. Set up under **Team Settings** → **Capabilities** → **Campaigns**. See the [Campaigns overview](/sections/documentation/campaigns/overview) for full detail. * **Target** users, groups, or a **CSV** (columns personalize the message). * **Schedule** now, at a set time, or by **each recipient’s local timezone**. * **Preview** the message and workflow form, then **send**; recipients get **Slack DMs** and tap **Respond**. * **Track** who finished and what they submitted on **insights**. *For example, run a quick pulse after rolling out a new internal tool—star ratings, “what’s confusing?,” optional contact—and wire the workflow so rough feedback opens a ticket for IT while the rest stays in insights.* ### **Receive Notifications in Your Serval Inbox** **Serval now has an Inbox** in the web app where you **receive notifications** about tickets, access, approvals, and more—organized in one list with a detail pane instead of chasing everything across Slack alone. Open **Inbox** from the sidebar, **filter** by notification type, team, or who triggered the update, switch to **unread only** for a tight queue, then use **Mark all as read** from the header menu when you are caught up. It is built for people who juggle **high notification volume** or **multiple teams** and need one surface to triage without losing context. See [Inbox](/sections/documentation/platform/inbox) in the platform docs for a quick tour. ### **Enable Web Search for the Help Desk Agent** The Help Desk Agent can now search the web when it needs information that isn't in your knowledge base. If a question falls outside your internal docs, the agent pulls from live web sources and surfaces an answer without bouncing the request back to IT. This means employees get faster resolutions on product questions, industry topics, or anything that lives outside your Confluence, Notion, or SharePoint. Your team doesn't have to manually maintain knowledge to cover every possible question. Enable it under **Team Settings** → **Capabilities**. See [Team settings](/sections/documentation/platform/team-settings#capabilities) for details. *For example, an employee asks about setting up a new tool your team hasn't documented yet. Instead of creating a ticket, the agent searches the web, finds the setup guide, and sends it directly in Slack.* ### **Connect AI Assistants with User MCP** Serval now supports MCP (Model Context Protocol), giving users a way to connect AI assistants and developer tools directly to their help desk. Once connected, tools like Claude can look up tickets, check access status, and interact with Serval on a user's behalf. This opens up a new class of workflows where AI assistants act as an interface layer into Serval — useful for power users and developers who want to work from their tools of choice rather than switching to Slack or the web portal. ### **Route Tickets Using Schedules in Assignment Rules** Assignment rules can use **schedules** so routing depends on when a ticket is escalated—for example, sending after-hours volume to an on-call group while business-hours traffic goes to the primary queue. Define reusable business hours in team settings, then reference them as a condition in your [assignment rules](/sections/documentation/ticketing/ticket-configuration/assignment). For how schedules work, how to create them, and how they combine with SLAs and assignment, see [Schedules](/sections/documentation/ticketing/ticket-configuration/schedules) in ticket configuration. ### **Delegate Approvals and Ticket Assignments** You can delegate your approvals and ticket assignments to another user or group, so work keeps moving when you're unavailable. When you're assigned as an approver or a ticket is assigned to you, Serval routes it to your delegate, who can act on your behalf. Delegation applies only to new approvals and assignments. Anything already assigned to you stays with you. This covers vacations, out-of-office blocks, and back-to-back meetings—without IT manually reassigning or escalating every request. Learn more in the [approvals documentation](/sections/documentation/workflows/Configure/approvals#delegation). *** ## **Ticketing** **Move tickets to teams using a structured form** Moving a ticket to a different team opens a structured form instead of a simple selector. You get more control over how the ticket is configured when it lands in the new team. **Trigger workflows when tickets move to a team** A new event trigger fires when a ticket is moved to a team. Use it to start a workflow, notify a channel, or run any automation based on team routing. **Keep Serval active after tickets change teams** When a ticket moves to a new team, Serval stays active and tries to resolve the request in that team before escalating. Moving a ticket no longer forces an immediate escalation. **Show org-wide catalog items to every user** When a workflow is set to "anyone in the org," its catalog items are visible to every user in the organization—not only members of the owning team—so company-wide self-service workflows surface correctly in the catalog. **View and edit custom fields from the ticket side panel** Custom fields are available in the ticket side panel so agents can see and edit them without opening the full ticket view. **Exclude journey tickets from standard ticket list APIs** Journey-associated tickets are excluded from standard ticket list API responses so routine lists stay focused on core help desk traffic. *** ## **Email** **Add To-field recipients as ticket subscribers** When an inbound email creates a ticket, anyone in the "To" field is now automatically added as a ticket subscriber. Previously only CC recipients were added. The subscriber UI has been updated to reflect both To and CC field recipients. **Forward inbound email images to Slack channels** Image attachments on inbound emails are now forwarded correctly to connected Slack help desk channels and appear alongside the ticket thread. *** ## **Knowledge** **Monitor knowledge sync status in the redesigned UI** The knowledge sync interface has been redesigned with better visibility into sync status across all connected sources — Confluence, Notion, SharePoint, and Google Drive. You can now see what's syncing, what's complete, and what needs attention without digging through settings. Sync performance is also faster under the hood, and long-running syncs no longer time out. *** ## **Notifications** **Notify users before access entitlements expire** Serval now sends a proactive Slack message and inbox notification one hour before a user's access entitlement expires. Notifications are off by default — enable them in notification settings. *For example, a contractor's access to your GitHub organization is set to expire at 5 PM. At 4 PM, they get a Slack notification with a link to request an extension before they're locked out.* **Reorganize notification settings by channel** The notification settings page has been reorganized by category with sub-pages for each notification channel. Microsoft Teams is now listed as a notification channel alongside Slack and email, bringing it to parity in the settings UI. *** ## **Access Management** **Set recommended access duration to none or infinite** When configuring access profiles, you can now set the recommended access duration to "None" or "Infinite" in addition to specific time windows. Previously, only specific durations could be set as recommended. **See access catalog updates without reloading the page** Adding a new role or resource to your access catalog now appears immediately without requiring a page refresh. **Open large access profiles in virtualized dialogs** Access profile dialogs are now virtualized and load smoothly for catalogs with thousands of groups, roles, or workflows. Previously, large catalogs caused slow or broken dialog behavior. **Search tickets, read field history, and manage teams via the public API** New public API capabilities include searching tickets and retrieving ticket field value history for integrations and reporting. Organization API key policies can also include `UPDATE_TEAM` and `DELETE_TEAM` for programmatic team membership updates. **Sort organization users by role** The organization settings users table now supports sorting by role. *** ## **Integrations** **Connect Gong to Serval workflows** Gong is available as a native integration so you can use Gong's REST APIs from Serval workflows. *** ## **Workflows** **Complete workflow forms with a compact layout on small screens** Workflow form inputs use a tighter layout on small screens so requesters can complete forms more easily on mobile. *** ## **Platform** **Brand magic link login with an organization-specific link** Magic link emails and the login experience can reflect your organization when users start from an org-specific login link. # March 5, 2026 Source: https://docs.serval.com/sections/release-notes/Mar-6-2026 This release includes team visibility controls, assets reference input types for workflows, external ticket subscribers, conditional forms in Slack, Microsoft Teams notifications, and more. ## **Highlights** * [Conditional Forms in Slack](#conditional-forms-in-slack) * [Team Visibility Controls](#team-visibility-controls) * [Add External Users as Ticket Subscribers](#add-external-users-as-ticket-subscribers) * [Assets Reference Input Type for Workflows](#assets-reference-input-type-for-workflows) ### **Conditional Forms in Slack** Slack forms now support conditional logic. Show or hide fields based on earlier answers, so users only see what's relevant to their specific request. * **Branch on any input**: Show a different set of fields depending on what the user selected in a previous question. * **Reduce form noise**: Users filling out a hardware request, onboarding form, or access request see only the fields that apply to them. * **Build in the workflow agent**: Describe your branching logic in plain language and the agent configures the conditions. *For example, build a device request form that shows Mac accessory options when the user selects MacBook, and Windows accessories when they select a PC, without sending irrelevant fields.* ### **Team Visibility Controls** You can now control which teams are visible in Slack, in the portal, and in Serval's auto-routing logic. Mark any team as hidden to remove it from the Slack drop-down, the portal selector, and automatic ticket routing. This is useful for sandbox teams, teams still being configured, or internal working groups that shouldn't be customer-facing. Hidden teams remain fully functional for members who access them directly. ### **Add External Users as Ticket Subscribers** You can now CC external email addresses on any ticket by adding them as guest subscribers from the Subscribers menu. Guest users receive email updates on the ticket but have no other access to Serval. This is useful for looping in vendors, contractors, or external stakeholders on a specific request without creating full accounts or exposing your Serval workspace. ### **Assets Reference Input Type for Workflows** Workflow forms now support a new "Assets Reference" input type. Link a field to Serval assets data and users get a live, searchable dropdown of real records at submission time. What you can do with it: * **Use live data instead of static choices**: Populate fields from real records like cost centers, locations, apps, or business units. * **Keep forms accurate over time**: New records appear automatically, so you do not need to manually update option lists. * **Map ServiceNow reference fields automatically**: During catalog ingestion, ServiceNow reference and list collector fields are mapped to assets references for you. * **Reduce input mistakes**: Users select valid records instead of typing free text, which improves downstream workflow reliability. *For example, build an access request form where a requester selects an active cost center from ServiceNow-backed entity data, then route approvals based on that selection.* Learn more in the [workflow inputs documentation](/sections/documentation/workflows/Configure/inputs#entity-reference). *** ## **Ticketing** **Ticket List Customization** You can now control row spacing in your ticket list and choose which fields display in each row. This makes it easier to scan queues at a glance. Due dates are also now visible directly in the ticket list, useful for teams tracking SLA windows without opening each ticket. **Updated Ticket Header Behavior** The ticket header layout has been updated with improved information density and more consistent behavior across ticket detail views. **Catalog UI Polish** Visual and interaction improvements across the catalog for a more consistent browsing experience across workflow and request catalog items. *** ## **Guidance** **Guidance Tickets Tab and Usage Metrics** Guidance now includes a Tickets tab that shows which tickets each guidance item has been applied to and tracks usage over time. See exactly how your guidance is driving agent behavior and which items are most active. *** ## **Help Desk Agent** **Multi-Level Access in a Single Message** The help desk agent now handles multi-level access resources in a single tool call instead of requiring a back-and-forth exchange. Users requesting access to tiered or nested resources get a faster, more direct response. **Guidance Accuracy Fix** Fixed a bug where the agent would pick the wrong guidance when multiple guidance items shared overlapping keywords. The agent now uses description-level scoping to resolve ambiguity, so the right guidance is applied consistently. **No More Retry Loops** The agent no longer gets stuck in a retry loop when the model returns both synchronous and asynchronous tool calls in the same message. This eliminates a class of long-running stalls on certain request types. *** ## **Knowledge** **Improved Retrieval Quality** Knowledge base retrieval has been upgraded across three areas: * **Better filtering**: GPT-4o mini is now used for knowledge filtering, improving speed and precision. * **Document reranking**: Retrieved results are reranked before being passed to the agent, surfacing the most relevant documents more consistently. * **Better chunking and storage**: Underlying chunk boundaries and storage keys have been reworked to improve retrieval fidelity on longer or more structured documents. *** ## **Access Management** **AWS OIDC Integration** General OIDC integrations are now supported for AWS. If your organization uses a non-Okta identity provider that supports standard OIDC configuration, you can now connect it to your AWS setup in Serval. **Slack Cards for Workflows and Access Extensions** Slack cards are now sent when workflows are triggered and when access extensions are requested. Users see a structured card in their Slack DM with the relevant context and action buttons inline. **"View Access Request" Fix in Slack** Fixed an issue where the "View Access Request" modal would not open when triggered from Slack. A loading state now displays while the modal loads, preventing the button from appearing unresponsive. **Public API for Approval Procedures** Approval procedures are now available in the Serval public API. Configure and manage your approval workflows programmatically. Documentation is live in the Serval API reference. *** ## **Integrations** **Microsoft Teams Notifications** Microsoft Teams users now receive real-time ticket and approval notifications directly in Teams. Approval requests surface inline in DMs with action buttons, and ticket updates thread to the right conversations. This brings Teams to parity with Slack for core notification delivery. **Zendesk** Zendesk ticket sync is now faster and more reliable. Ticket assignees are preserved during transient sync errors, and user lookups are now cached to reduce Zendesk API calls during bulk ingestion, improving sync performance for large Zendesk instances. *** # May 13, 2026 Source: https://docs.serval.com/sections/release-notes/May-13-2026 The Serval UI is available in English, German, Spanish, French, French (Canada), Japanese, Portuguese, Portuguese (Brazil), and Russian. Guidance is now Skills, reviewers can publish approved knowledge updates into Notion, Slab, Confluence, Freshservice, and ServiceNow, and campaigns now run on Microsoft Teams. ## Highlights * [Nine languages in the Serval UI](#nine-languages-in-the-serval-ui) * [Guidance is now Skills](#guidance-is-now-skills) * [Publish approved updates into third-party knowledge bases](#publish-approved-updates-into-third-party-knowledge-bases) * [Send campaigns through Microsoft Teams](#send-campaigns-through-microsoft-teams) ### **Nine languages in the Serval UI** The Serval UI is available in **English, German, Spanish, French, French (Canada), Japanese, Portuguese, Portuguese (Brazil),** and **Russian**. Each user picks a display language from the user menu, and the choice is stored per user so it follows you across devices. A built-in glossary keeps Serval-specific terms (skills, workflows, etc.) consistent across every language instead of being translated literally. ### Guidance is now Skills Guidance has been renamed to **Skills** — the label now matches how teams usually talk about reusable in-product instructions and playbooks. Some UI may still show **Skills (Guidance)** during the rename. Behavior is unchanged; this is a surface rename only. ### **Publish approved updates into third-party knowledge bases** Serval has suggested improvements from ticket activity for a while — gaps where your documentation is thin, answers that have gone stale, and what the Help Desk Agent answered when nothing in your knowledge base covered it. When reviewers approve a suggestion, Serval **writes the update into the knowledge base that lives in your connected third-party system** — **Notion, Slab, Confluence, Freshservice,** or **ServiceNow** — so canonical help content stays where your team already maintains it. *For example, when the Help Desk Agent resolves the same question three times with an answer that is not documented in Confluence, Serval drafts an article, sends it through review, and on approval publishes it into that Confluence knowledge base so the next person to ask sees the answer in the same library your authors already use.* ### Send campaigns through Microsoft Teams Campaigns now work in Microsoft Teams — same audience, message, response workflow, and reporting as Slack campaigns. *For example, an IT team running mandatory MFA enrollment can send the same campaign to their Slack users and their Teams users in parallel, route both audiences' replies into the same response workflow, and watch a single completion report.* *** ## Workflows **Trigger workflows on ticket attribute changes** Workflows can now be triggered when a ticket attribute changes — starting with **labels**. Adding or removing a label on a ticket can kick off a downstream workflow. **Drag to reorder assignment rules** Assignment rules can now be reordered by dragging. Rules higher in the list take precedence when multiple rules match, so the order in the UI directly controls assignment behavior. **Public API: update users' phone numbers** `UpdateUser` now accepts a phone number, so workflows that collect phone numbers (for example from HRIS, IdP, or self-service forms) can write them back to user profiles. *** ## Access management **Approval delegation extends to ticket assignments** The delegate concept — where an approver can hand off approvals to another user during PTO or temporary leave — now extends to ticket assignments. If you're delegated, you receive the assignments too. **Auto-approve when creator equals approver** When a user creates an access request or change request for which they are also the configured approver, Serval now auto-approves it instead of asking them to approve their own request. *** ## Ticketing **Label color picker** Pick a color for every label at create and edit time. Label colors are aligned with the eight status colors used elsewhere in the product, so badges feel consistent across the UI. **CC arbitrary users on email replies** When replying to an email ticket, you can now add users to the Cc line as if it were an email client — they'll receive the reply and be invited to the ticket as subscribers. **Slack agent thread titles update dynamically** In Slack DMs with the Help Desk Agent, thread titles now update to reflect the actual conversation as it unfolds, instead of staying frozen on the first message. **Video reference attachments on tickets** Tickets now support video reference attachments — useful for screen recordings attached to bug reports, walkthroughs, or onboarding journey tasks. Videos render in an inline player. *** ## Integrations **LinkedIn** LinkedIn is now available as a native integration. Common use cases include posting recruitment events from a workflow and pulling profile data into onboarding flows. **DocuSign** DocuSign is available as a native integration. Send envelopes, check signature status, and retrieve completed documents from a Serval workflow. **Medallia** Medallia is available as a native integration, enabling customer-feedback signal to flow into Serval workflows and tickets. **Typeform** Typeform is available as a native integration via OAuth 2.0. Use Typeform responses as triggers or inputs to Serval workflows. **PandaDoc** PandaDoc templates can now be managed natively inside Serval and used as inputs to workflows that send documents for signature. **RSA, IVM, NetSuite** RSA, IVM, and NetSuite are now available as native integrations. **More control over integration scopes** * **Intune:** Connecting Intune now offers two preset scope bundles — **read-only** and **read/write** — covering the most common device-management use cases without requiring admins to assemble individual scopes by hand. * **Microsoft:** Microsoft integrations now expose the underlying scopes inside each bundle, so admins can connect with only the specific scopes their workflows need rather than the full bundle. * **Confluence:** Confluence integrations now support custom scopes. Previous connections were overpermissioned by default — admins can now scope down to exactly what's needed. * **Slack:** The Slack integration now supports custom OAuth scopes. Add only the scopes your workflows need (for example user-group management) rather than accepting the default scope bundle. **Audit log export to SIEM via WorkOS** Send Serval audit logs to your SIEM through WorkOS. Configure once in settings and Serval streams audit events to the destination of your choice. *** ## Catalog and packages **Publish approved updates into third-party knowledge bases** See [Highlights](#publish-approved-updates-into-third-party-knowledge-bases). Supported when the connected knowledge base is hosted in **Notion, Slab, Confluence, Freshservice,** or **ServiceNow**. **Target user for service-catalog form items** Service-catalog items that use forms can now specify a target user — the workflow runs against that user rather than the requester, useful for manager-driven flows like "request equipment for my new direct report." *** ## Platform **Drafter role** A new **Drafter** role lets users draft workflows, skills, and other resources without permission to publish. Useful for teams that want a review step before changes go live. **Catalog Import lives in Capabilities** Catalog Import (renamed from Service Catalog last release) now lives in **Capabilities** and is generally available — no feature flag required. # May 20, 2026 Source: https://docs.serval.com/sections/release-notes/May-20-2026 Send campaigns over email, configure Help Desk Agent escalation behavior per Slack channel, new Readonly Agent role on agent teams, and select app instances in workflow steps. ## Highlights * [Send campaigns over email](#send-campaigns-over-email) * [Configure Help Desk Agent escalation behavior](#configure-help-desk-agent-escalation-behavior) * [Readonly Agent role](#readonly-agent-role) * [Select app instances in workflow steps](#select-app-instances-in-workflow-steps) ### Send campaigns over email Campaigns can now be delivered via email in addition to Slack, so you can reach employees wherever they actually work. Configure your campaign the same way you always have and pick email as the destination. *For example, an IT team rolling out a new VPN policy can send the announcement directly to employees' inboxes, with a clean record of who received it.* ### Configure Help Desk Agent escalation behavior You can now set how the Help Desk Agent handles escalation on each connected Slack channel. Under **Help Desk Agent**, pick the mode that matches how noisy the channel is and how much you want Serval to speak before handing work to a human. **Help Desk (When Relevant)**. Serval replies to the initial request only when it has relevant context to help. If it needs to escalate on the first message, it hands off without posting a filler reply (you'll see a handed-off signal in the thread). **Help Desk (Always Respond)**. Serval replies on tickets and follows the usual path: respond first, then escalate to a human when it cannot resolve the request. *For example, in a request where a user asks for help for something Serval has no information or functionality for, **Help Desk (When Relevant)** keeps Serval from repeating the user's request back and saying it has escalated the ticket, while **Help Desk (Always Respond)** fits a dedicated support channel where every request should get an immediate acknowledgment.* ### Readonly Agent role A new **Readonly Agent** team role is available when you add members to an agent team. Readonly Agents can view tickets, activity, and agent behavior but cannot make changes. *For example, a security auditor or department head can be added to the IT Help Desk Agent team to monitor volume and activity without risking accidental edits.* ### Select app instances in workflow steps If your workspace connects multiple instances of the same app, you can now select the specific instance you want a workflow step to use. Instances are grouped in a clean dropdown so there is no ambiguity about which one gets called. *For example, a company with separate Okta tenants for US and EU employees can build workflows that explicitly target the right tenant at each step.* Learn more in the [workflow building documentation](/sections/documentation/catalyst/building-workflows#choose-which-instance-a-step-uses). *** ## Workflows **Approval send-back** Inline approvals now support a "Send Back" option alongside Approve and Deny, so approvers can return a request for more information without rejecting it outright. **Cross-field filters** Workflow form fields of type Entity Reference can now filter their available options based on the value of another field in the same form, making dynamic forms much cleaner to configure. **Scheduled workflow fire time** The exact time a scheduled workflow triggers is now available as a variable you can reference inside the workflow itself. **Submit with Enter or Cmd+Enter** Users can now choose whether pressing Enter submits a message or inserts a new line, configurable in personal settings. *** ## Ticketing **Catch-all queue mode** A new queue configuration option makes all incoming tickets private by default, giving you a clean access baseline before routing rules apply. **Paginated audit logs** Audit logs are now paginated and filterable, making it practical to search and review activity at scale. **Ticket Viewed audit event** Viewing a ticket now generates an audit event, adding a layer of traceability for compliance-sensitive teams. **Retry canceled workflow runs in journeys** When a journey subtask's workflow run is canceled, you can retry it from the subtask view, the subtask hover card, or the workflow run sidepanel. Canceled runs show a clear status and a **Retry** action so you do not have to recreate the subtask from scratch. *** ## Integrations **Tailscale** Tailscale is now available as a native integration. **DockerHub** DockerHub is now natively integrated with support for both personal access tokens and organization access tokens. **Factorial** Factorial is now available as an integration. **Email allowlist subdomains** Email allowlists now support subdomain entries, so you can cover an entire domain family with a single rule rather than listing each subdomain individually. **Dark and light mode logos** Workspaces can now set separate logos for dark and light mode, so your Serval environment matches your brand in both themes. **Hibob** Custom fields and UI improvements are now available for Hibob-connected workspaces. # May 27, 2026 Source: https://docs.serval.com/sections/release-notes/May-27-2026 Collect responses with email campaigns, organize workflows into folders, and set a default triage team for ambiguous requests. ## Highlights * [Attach response workflows to email campaigns](#attach-response-workflows-to-email-campaigns) * [Organize workflows into folders](#organize-workflows-into-folders) * [Set a default triage team](#set-a-default-triage-team) ### Attach response workflows to email campaigns Response workflows, previously available only in Slack DM and Microsoft Teams DM, are now supported in email campaigns. Recipients can interact with the Respond button and submit structured form data directly from a campaign email. *For example, an IT team can email employees with low usage of a SaaS tool, and depending on their response, trigger a workflow to deprovision access.* ### Organize workflows into folders Workflows can now be organized into folders, making it much easier to manage large automation libraries. Create folders by team, use case, or product area to keep your workspace clean as your automation footprint grows. *For example, a team with workflows for onboarding, offboarding, and device provisioning can now keep each category in its own folder instead of scrolling through a flat list.* Learn more in the [organizing workflows documentation](/sections/documentation/workflows/Manage/organize#folders). ### Set a default triage team Admins can now configure a default triage team for requests that Serval cannot confidently route to a specific team. *For example, an IT admin can designate a general help desk team as the fallback so that unusual or edge-case requests always have someone on them from the start.* *** ## Ticketing **Automatically infer ticket status from subtasks** Tickets with subtasks now infer their status from those subtasks automatically, so parent tickets stay up to date without manual changes. *** ## Access management **Redesigned access profiles page** Access profiles have been redesigned with an expandable list view, and every team now automatically gets a built-in "all team members" profile. You can expand any profile to see its criteria, whether that's specific roles within a team or the full team, making it easier to audit and configure who can trigger a workflow. **Redesigned access page** The access page now displays a full access catalog, giving employees a clear view of what they can request and how. Employees can review their past requests in the "History" tab of the page. *** # November 11, 2025 Source: https://docs.serval.com/sections/release-notes/Nov-10-2025 This release includes highlights like guidance suggestions, tasks for tickets, webhook-triggered workflows, platform improvements, and 7 new integrations. ## Highlights * [Approve Guidance Suggestions](#approve-guidance-suggestions) * [Add Tasks to Tickets](#add-tasks-to-tickets) * [Trigger Workflows via Webhook](#trigger-workflows-via-webhook) * [Duplicate Workflows Across Teams](#duplicate-workflows-across-teams) ## Approve Guidance Suggestions Turn manual resolutions into reusable automations automatically. Serval suggests adding or updating guidance when teammates manually resolve tickets. Suggestions appear in the Guidance platform, via direct message in Serval's Slack app, or directly in tickets, where managers can approve or reject them. Anyone can also ask Serval to remember guidance directly from any conversation. The more you use Serval, the more suggestions you receive. Anyone in Serval can request to add guidance by instructing Serval to remember. ## Add Tasks to Tickets Add tasks to tickets and assign them across teams so multiple people and workflows can work in parallel. Set parent tickets to organize existing tickets into tasks. Tasks can combine automated workflows and manual work, and workflows can create tasks automatically. Use the "Relation" filter to view parent or child tickets. Serval uses a two-layer ticket and task hierarchy, so tasks cannot have sub-tasks. Set parent tickets to organize tasks. ## Move Tickets Between Teams Transfer tickets between teams to route requests to the right team for resolution, even if you aren't a manager or agent in the receiving team. If you're not in the receiving team, only that team will have access after the transfer. ## Attach Any File Type to Tickets Users can now attach any file type to tickets. ## Route Requests to Team Slack Channels Route requests to dedicated Slack channels for each team. Create a Slack 'Team Inbox' to receive all your team's tickets, or a 'Team Inbox on Escalation' to receive only escalated tickets, so there's a single place to review all tickets that require manual resolution. *For example, #serval-IT receives all IT requests, while #serval-IT-escalated receives only tickets requiring manual review.* ## Trigger Workflows via Webhook Trigger Serval workflows from any external system that supports webhooks. Serval generates a webhook URL and secret key to configure in your apps. *For example, when someone submits a reimbursement in Ramp, the webhook triggers a workflow to notify the approver in Slack for immediate approval.* ## Select Workflow Type Select your workflow type to guide the workflow builder before you start building. Choose from help desk, team-only, scheduled, or webhook-triggered workflows. Or let AI choose for you. ## Duplicate Workflows Across Teams Copy workflows from one team to another to replicate successful automations. You can copy workflows to teams where you have manager rights. ## Update Tickets via Serval API Build workflows that [update Serval tickets via API](https://docs.serval.com/api-reference/ticket-api/update-ticket) to automate ticket management from any system in your tech stack. ## Duplicate Applications Across Teams Duplicate integrated applications to other teams in one click to replicate successful setups without reconfiguring from scratch. You can copy applications to any team where you have manager rights. ## New Integrations [**Persona**](https://docs.serval.com/sections/integrations/persona#persona)\ Identity verification. [**CrowdStrike**](https://docs.serval.com/sections/integrations/crowdstrike#crowdstrike)\ Cybersecurity monitoring and incident response workflows. [**Envoy**](https://docs.serval.com/sections/integrations/envoy#envoy)\ Visitor management workflows. Added Envoy Installable workflows. [Figma](https://docs.serval.com/sections/integrations/figma#figma)\ Collaborative interface design application. [**Datadog**](https://docs.serval.com/sections/integrations/datadog)\ Cloud-based monitoring and analytics platform to monitor infrastructure, applications, and logs in real-time. [Ashby](https://docs.serval.com/sections/integrations/ashby#ashby)\ Applicant Tracking System with recruiting analytics. [BambooHR](https://docs.serval.com/sections/integrations/bamboohr#bamboohr)\ Human Resources Information System (HRIS). ## Knowledge Base Updates [**Zendesk Knowledge Base**](https://docs.serval.com/sections/integrations/zendesk#zendesk)\ Ingest articles from your Zendesk KB. ## Platform UI Updates **Ticket Detail Improvements**\ Cleaner layout and timezone information on the ticket list. **Access Request Log Exports Additions**\ Export log reports from the role portal with additional compliance and audit details. ## Speed and Performance Improvements **Improved Load Times**\ Faster load times on repeat visits and offline capabilities through improved caching. # November 18, 2025 Source: https://docs.serval.com/sections/release-notes/Nov-18-2025 This release includes highlights like always-used guidance, custom email responses, ticket navigation, integration updates and platform UI/performance improvements. ## Highlights * [Set Guidance as "Always-Used"](#set-guidance-as-always-used) * [Set Custom Email Auto-Response](#set-custom-email-auto-response) * [Navigate Between Tickets](#navigate-between-tickets) * [Set Custom SLA Time](#set-custom-sla-time) * [Filter by Ticket Type](#filter-by-ticket-type) ## Set Guidance as "Always-Used" Set important guidance as "always-used" to ensure the help desk agent always includes this guidance when considering how to respond to every ticket. This ensures Serval follows essential guidance—like compliance requirements, ticket routing, or security procedures—in every ticket resolution. *For example* * *Set tone of voice to define how the help desk agent interacts with users* * *Set ticket assignment rules to specific owners based on ticket content* * *Set data protection guidance to guarantee compliance on all data-related requests* * *Set security incident response guidance to ensure the AI agent follows your security protocols on every ticket* ## Set Custom Email Auto-Response Customize auto-response messages for your team's email intake. Users receive immediate confirmation that their request was received. When someone emails your team, they receive your confirmation message immediately. Serval will continue to respond as usual via email after that initial message is sent. *For example, send "Thanks for reaching out to IT! We typically respond within 4 hours" or "Security team has received your request. For urgent issues, please Slack @security-oncall."* ## Navigate Between Tickets Navigate between tickets in your list without leaving ticket details: * Move between tickets with **J/K keys** or click the **↑/↓** arrows on the top right * Returns to your position when you navigate back to the list ## Manage Ticket Subscribers via API Build workflows or integrations that manage ticket subscriptions programmatically with new API endpoints: * **POST** `/v2/tickets/{ticket_id}/subscribers` - [Create subscribers](https://docs.serval.com/api-reference/ticket-api/create-ticket-subscribers) * **GET** `/v2/tickets/{ticket_id}/subscribers` - [List subscribers](https://docs.serval.com/api-reference/ticket-api/list-ticket-subscribers) * **DELETE** `/v2/tickets/{ticket_id}/subscribers` - [Delete subscribers](https://docs.serval.com/api-reference/ticket-api/delete-ticket-subscriber) *For example, when building a workflow, automatically subscribe your security lead to all "Add user to Okta" tasks in your onboarding workflow so they're notified whenever someone is added to Okta.* ## Set Custom SLA Time Create a more precise Service Level Agreement (SLA) by editing the SLA time to be any custom duration in days, hours, and minutes. ## Filter by Ticket Type Filter by ticket type to better organize ticket progress. View root-level "requests" or filter for "tasks" (tickets that belong to a parent request). ## Integration Updates **\[New]** [**Rapid7**](https://docs.serval.com/sections/integrations/rapid7) Comprehensive cybersecurity platform that provides vulnerability management, incident detection and response, application security testing, and log management. *For example, pull in the device scans and vulnerability reports from Rapid7 and then cross-reference that with the assets in Jamf. Create a task for users to update their laptop software if vulnerabilities are detected.* [**Freshservice Integration Updates**](https://docs.serval.com/sections/integrations/freshservice) Before, you had to be an Account Administrator to connect Freshservice to Serval. Now you can connect with just workspace-level permissions. Serval automatically filters to show only the workspaces you can access and validates your connection with health checks (workspace access, ticket form fields, and ticket listing). ## Platform UI Updates **Collapsible Side Bar** The sidebar is now collapsible to make navigation easier. Icons have been added to all menu items. Teams each have unique icons to more quickly differentiate across teams. **Ticket Move Improvements** Clearer confirmation and next steps after moving tickets between teams. Warning notification that you will lose access to a ticket after moving a ticket you have not interacted with. **Child Ticket Visibility** All child tickets (tasks) are now visible at the top of parent tickets, including tasks created by workflows, making it easier to track all related tasks in one place. **Workflow Change Tracking** Serval tracks unsaved workflow changes and warns only before navigating away from workflows that have been edited to prevent accidental loss of edits. **User Mention Popovers** Improved handling of deactivated users with clearer visual styling. ## Speed and Performance Improvements **Faster Workflow Loading** Workflows load significantly faster in the workflow builder. # November 26, 2025 Source: https://docs.serval.com/sections/release-notes/Nov-26-2025 This release includes highlights like updates to knowledge base management, incident management tickets, AI-powered automation suggestions with workflows, and integration updates. ## Highlights * [Manage Knowledge Base from the Sidebar](#manage-knowledge-base-from-the-sidebar) * [Introduce Incident Management](#introduce-incident-management) * [Enhance AI Suggestions with Workflows](#enhance-ai-suggestions-with-workflows) * [Enable AI Agent to Remain Active After Escalation](#enable-ai-agent-to-remain-active-after-escalation) ## Manage Knowledge Base from the Sidebar A dedicated Knowledge Base section in the Serval sidebar gives you a centralized place to manage all your connected knowledge sources like Notion, Confluence, Google Workspace, Freshservice, and Zendesk. Control what information Serval's AI agent uses for faster, more accurate help desk resolutions without leaving your workflow. * **Sync status filtering:** View and manage knowledge items by synchronization state. Filter by 'All statuses', 'Syncing', 'Synced', 'Failed', and 'Waiting' on both team and application-specific knowledge pages. Folders now show a 'Failed' status if any child item has failed to sync * **Manual sync:** Use the Manage sources button to synchronize sources on demand (sources automatically sync every four hours) **Manually Sync Sources** ## Introduce Incident Management Create, view, and filter incident tickets within Serval to improve visibility and management of critical issues affecting multiple users. * **Incident ticket type:** Manage high-priority issues that affect multiple users * **AI-powered incident linking:** The AI Help Desk Agent intelligently detects when a user's request is related to an ongoing incident, automatically linking tickets and providing relevant updates or resolutions directly within the conversation * **Workflow incident creation:** Create incident tickets directly from your automated workflows alongside standard request tickets * **Filter incidents:** Use Ticket Type to filter for all incidents *For example, when multiple employees report that Cloudflare is down, Serval detects the pattern, creates an incident ticket, and automatically links all related requests. If another user asks about things like ChatGPT is down, the help desk agent can link to the original incident ticket and know that this is likely because Cloudflare is down.* **Ask Serval to Build an Automation Directly from a Ticket** Building automation from a ticket ## Enhance AI Suggestions with Workflows Serval's AI Help Desk Agent now suggests creating custom workflows, installing pre-built workflows from the library, and connecting new applications to unlock further automation. This moves beyond guidance suggestions to proactive recommendations that expand your automation capabilities. * **Finding suggestions:** Review and approve suggestions both by clicking "Suggestions" in the top right corner of Guidance or in Workflows * **Workflows and suggestions:** Ask Serval to suggest workflows by tagging @Serval and requesting a specific automation, such as "please suggest a new workflow to add a user to a private channel" *For example, after Serval couldn't send emails to Ashby candidates, Serval suggests creating a workflow to send emails to Ashby candidates with guidance around when to do so. You can edit and approve this workflow before publishing.* ## Tag Users in Guidance Mention specific users directly within your guidance documents by typing @ and selecting their name from a list. This creates clearer, more personalized instructions in your team's knowledge base, making it easier for Serval's AI and human agents to reference relevant individuals when providing support. This ensures the right people are automatically looped in on relevant requests without manual handoffs. *For example, tag @Sarah Kramer in guidance about security exceptions so the AI agent knows to loop her in on relevant requests.* ## Enable AI Agent to Remain Active After Escalation Serval's AI agent can now remain active on a ticket even after it has been escalated to a human agent. Previously, the AI would disengage upon escalation. With this change, the AI continues to provide relevant guidance and support alongside your team, ensuring continuous assistance throughout the ticket's lifecycle and reducing resolution time. ## Integration Updates [**\[New\] Firstbase**](https://docs.serval.com/sections/integrations/firstbase) Automate hardware lifecycle management with Firstbase, a platform for procuring, deploying, and managing IT equipment globally. This integration streamlines device onboarding, retrieval, and redeployment for remote and in-office teams. [**\[New\] CRXplorer**](https://docs.serval.com/sections/integrations/crxplorer) Analyze Chrome extensions for security vulnerabilities, permissions risks, and malware with CRXplorer. This integration enables automated extension scanning workflows to monitor browser security across your organization. [**Jira Integration Updates**](https://docs.serval.com/sections/integrations/jira) Improved Jira integration. Serval intelligently converts headings, lists, code blocks, and inline styles between Jira's native format (ADF) and Markdown. [**Freshservice Integration Updates**](https://docs.serval.com/sections/integrations/freshservice) Improved reliability of ticket assignments for Freshservice integration. This update refines the logic for assigning tickets to users within Freshservice, ensuring that tickets are consistently and correctly routed to the designated agents. ## Platform Updates **Sync Tickets to New Team Channels Automatically** When a ticket is moved to a new team, all configured channels now automatically sync with that ticket. However, Serval follows the syncing configuration for the new channel. So if syncing is turned off in that new channel, Serval will not sync. *For example, if a ticket is moved from IT to HR, the Jira team associated with HR will now ingest this ticket. This ensures ticket visibility across all relevant systems without manual intervention.* # October 2, 2026 Source: https://docs.serval.com/sections/release-notes/Oct-02-2026 More flexible ticket views, BYO OAuth for Google Workspace, customizable avatars, and mirror Slack user groups into Serval. ## Highlights * [More flexible ticket views](#more-flexible-ticket-views) * [Bring your own OAuth for Google Workspace](#bring-your-own-oauth-for-google-workspace) * [Customizable avatars for people and teams](#customizable-avatars-for-people-and-teams) * [Mirror your Slack user groups into Serval](#mirror-your-slack-user-groups-into-serval) * [See who attached an item to a ticket, and why](#see-who-attached-an-item-to-a-ticket-and-why) * [See ServiceNow catalog item answers in the synced ticket](#see-servicenow-catalog-item-answers-in-the-synced-ticket) ### More flexible ticket views In the **Tickets** page, you can add columns for your own custom fields and for SLA timers, search your custom fields directly from the filter menu, and filter a saved view by ticket title, so the list shows the right tickets with the right details side by side. See [Filter and sort tickets](/sections/documentation/ticketing/manage-collaborate/filter-sort). ### Bring your own OAuth for Google Workspace You can now connect Google Workspace to Serval with an OAuth app registered in your own Google Cloud project. Once someone in your domain authorizes it, workflows and knowledge sync can use Docs, Sheets, Forms, Drive, and Calendar. Previously, these APIs required a service account with domain-wide delegation. The connection is limited to the scopes you grant and to what the authorizing account can already access. See [Google Workspace](/sections/integrations/google-workspace). ### Customizable avatars for people and teams Serval now gives every person and team a generated avatar when there's no uploaded photo, and you can choose its color. Names and teams stay easy to tell apart across the app instead of falling back to a plain placeholder. ### Mirror your Slack user groups into Serval When Slack is connected, Serval can now bring in your Slack user groups and mirror them as Serval groups, keeping their membership in sync. The groups your team already maintains in Slack become available inside Serval without rebuilding them by hand. *For example, a Slack "@security-oncall" user group can appear as a Serval group and stay up to date as people join or leave it in Slack.* See [Slack](/sections/integrations/slack). ### See who attached an item to a ticket, and why Associated items on a ticket now record who attached them, and when Serval linked one, why. When several people work a ticket, it's clear where each linked asset or record came from. *For example, you can see that an agent linked a specific laptop to a hardware request, rather than guessing how it got there.* ### See ServiceNow catalog item answers in the synced ticket When a ticket comes in from a ServiceNow requested item, the answers the requester gave on the catalog item are now included in the initial ticket message. See [ServiceNow](/sections/integrations/servicenow). *** ## Tickets **Drill into ticket categories one level at a time** The ticket category picker now opens one level at a time, so you can navigate a deep category tree without scrolling a single long list. **Copy a ticket's ID from its header** A ticket's header now has a control to copy its ID, so you can paste a precise reference into a chat or another tool. **See the ticket type on Kanban board cards** Cards on the Kanban board now show their ticket type, so you can tell requests, incidents, and other types apart at a glance. ## Catalyst **Link background agent runs from a chat** Catalyst can now reference a background agent run from within a chat, so you can follow a long-running task from the conversation that started it. **Review and dismiss pending suggestions** Catalyst can now list the suggestions waiting on you, present them for approval, and let you dismiss the ones you don't want. **Copy a completed response** Completed Catalyst responses now have a copy button, so you can reuse an answer somewhere else in one click. ## Databases **Rolling date filters for databases** Database views can now filter on rolling date windows instead of fixed calendar dates. A filter like "in the last 7 days" keeps meaning the same thing every day, so a saved view stays current without anyone editing the dates. See [Browse and query databases](/sections/documentation/databases/browsing-and-querying). ## Platform **See when each API key was last used** The API keys list now shows each key's last activity, so you can spot keys that haven't been used recently. **Set an organization session idle timeout** An organization can now configure how long a session can stay idle before it ends, giving admins control over how quickly inactive sessions are signed out. ## Integrations **New integrations in** Serval adds an [xMatters](/sections/integrations/xmatters) integration for alerting and on-call workflows, plus read-only [Nautobot](/sections/integrations/nautobot) and [Oracle Enterprise Manager](/sections/integrations/oracle-em) integrations for inventory and CMDB ingestion (both in beta). **New workflow actions for Twilio and Workday** Workflows can now send a WhatsApp message through Twilio, and can make a per-user [Workday](/sections/integrations/workday) Business Process request that acts as the running user. **Bring requester files from the original Freshservice ticket into Serval** Serval now ingests ticket-level attachments from Freshservice, so files a requester attached to the original ticket reach Serval along with the conversation. See [Freshservice](/sections/integrations/freshservice). **Kandji is now Iru** The Kandji integration has been renamed to Iru across the app and docs to match the vendor's new name. # September 4, 2026 Source: https://docs.serval.com/sections/release-notes/Sep-04-2026 Gate skills by access profile, live agent in the embedded widget, a refreshed Analytics home, and Jira project routing. ## Highlights * [Gate skills by access profile](#gate-skills-by-access-profile) * [Schedule when an approval delegation applies](#schedule-when-an-approval-delegation-applies) * [Live agent in the embedded chat widget](#live-agent-in-the-embedded-chat-widget) * [A refreshed Analytics home](#a-refreshed-analytics-home) * [Route Jira tickets by project and workflow](#route-jira-tickets-by-project-and-workflow) ### Gate skills by access profile You can now use access profiles to decide which skills apply to which people. Attach an access profile to a skill, and Serval only offers it to requesters whose profile matches that audience. See [Access profiles](/sections/access-management/configuration/access-profiles). ### Schedule when an approval delegation applies Approval delegation rules can now carry an active window. Instead of delegating your approvals indefinitely, set a start and an end so the delegation turns on and off on its own. *For example, delegate your approvals to a teammate for the week you're away, and they revert to you automatically when the window closes.* See [Approvals](/sections/documentation/workflows/Configure/approvals). ### Live agent in the embedded chat widget The embedded Serval chat widget now supports live-agent handoff. When a conversation moves from Serval to a person, the requester sees the human agent's replies in the same widget and can start or end the live session from controls built into the chat, so the whole exchange stays in one place. ### A refreshed Analytics home The Analytics landing page now opens on the work you check most. A strip of your dashboards runs across the top, an at-a-glance SLA summary sits alongside the existing charts, and the separate tab strip is gone in favor of this single home. You can star the dashboards you rely on so they lead the list, and pin any dashboard to the sidebar for one-click access. See [Analytics](/sections/documentation/platform/analytics). ### Route Jira tickets by project and workflow When Serval creates tickets in Jira, you can now choose the destination project more precisely. Set a default project for tickets that don't match a specific route, and route ticket creation through a workflow that picks the project from the ticket's details. You can build these routing workflows directly in Catalyst. See [Jira](/sections/integrations/jira). *** ## Ticketing **Sub-group the team ticket list** The team ticket list now supports a second grouping level, so you can break a group down further (for example, by status within assignee) the way you would in a tool like Linear. **Keyboard navigation for the ticket list** Move through the ticket list and open tickets from the keyboard, without reaching for the mouse. **Show visibility groups as a column** The ticket list can now display each ticket's visibility groups as a column, so you can see at a glance who a ticket is scoped to. **Filter analytics by assignment group** The analytics Overview and SLA pages can now be filtered by assignment group, narrowing the metrics to the group you pick. ## Help desk **Deterministic caller verification for voice** Serval now verifies the caller at the start of a phone call using a defined verification step, so a voice conversation only proceeds once the caller's identity is confirmed. See [Phone channel](/sections/documentation/helpdesk/phone). ## Knowledge **Scope SharePoint discovery to chosen sites and folders** When connecting SharePoint as a knowledge source, you can now pick the specific sites and folders to ingest instead of crawling everything. See [connected sources](/sections/documentation/knowledge-base/connected-sources). **Per-item knowledge sync history** Each knowledge item now records a sync history, so you can see when it last synced and what happened. ## Platform **Team managers can create their own API keys** Team managers can now generate, view, and revoke scoped API keys for their team from team settings, without going through an org admin. **Grant approval override through custom roles** The ability to override an approval can now be granted through a custom role, so you can give a role exactly that permission without broader access. **Brand the embedded widget from settings** Admins can now set the embedded widget's name, logo, and a dedicated square launcher icon from settings. **Inbox view menu and keyboard approval queue** The inbox gains a view menu for switching what it shows, and you can work through pending approvals from the keyboard. ## Integrations **New native integrations** Serval adds native integrations for [Palo Alto Strata Cloud Manager](/sections/integrations/palo-alto-strata-cloud-manager), Cisco Catalyst Center, [Uyuni](/sections/integrations/uyuni), [VMware vCenter](/sections/integrations/vmware-vcenter), [Socket](/sections/integrations/socket), [Have I Been Pwned](/sections/integrations/haveibeenpwned), [Linx Security](/sections/integrations/linx), and [Figma](/sections/integrations/figma). **Ingest Zendesk groups** Serval can now ingest Zendesk groups as Serval groups, so Zendesk group membership is available for routing and access. **Delta sync for Active Directory** The LDAP/Active Directory integration now syncs users and groups incrementally, picking up just the changes since the last sync. **Run Workday calls as the acting user** Serval can now make Workday Person REST calls as the acting user, so results respect that user's own Workday permissions. See [Workday](/sections/integrations/workday). **Freshservice resolution notes as internal notes** When Serval ingests a Freshservice ticket, its resolution notes now come in as internal notes. **Drive ticket status from GitHub pull requests** A connected GitHub app can now move a ticket's status in response to pull request events, so a linked ticket keeps pace with the PR. ## For developers **Public API additions** The public API gains several new capabilities: read and manage assignment rules ordered by priority, create custom field definitions, move a knowledge document between locations, and read knowledge document content as Markdown. **Push and pull skills with the CLI** The Serval CLI can now push and pull Help Desk and Catalyst skills alongside the rest of a team's configuration. # September 11, 2026 Source: https://docs.serval.com/sections/release-notes/Sep-11-2026 Automatically reclaim unused licenses, attach a native form to a journey task, rank knowledge articles by audience, trigger workflows from ticket feedback, and more. ## Highlights * [Automatically reclaim unused licenses](#automatically-reclaim-unused-licenses) * [Attach a native form to a journey task](#attach-a-native-form-to-a-journey-task) * [Rank knowledge articles by audience](#rank-knowledge-articles-by-audience) * [Trigger workflows from ticket feedback and agent replies](#trigger-workflows-from-ticket-feedback-and-agent-replies) * [Connect Box folders and ingest Office files from Google Drive](#connect-box-folders-and-ingest-office-files-from-google-drive) ### Automatically reclaim unused licenses Serval can now automatically take back application access that people have stopped using. Attach a reclamation policy to a role, set the days of inactivity before access is due to be reclaimed, and Serval surfaces the grants that pass that threshold. A policy with reviewers routes each one to a person who reclaims or dismisses it, and a policy with no reviewers reclaims automatically. Every reclaim deprovisions through the role's existing provisioning method and opens a ticket you can follow. See [Reclamations](/sections/access-management/reclamations). ### Attach a native form to a journey task Native forms, which allow for dynamic fields and built-in workflows, can now be attached to journey tasks. Ask Catalyst to build one onto the task, and the person assigned sees the form itself in their journey view. Form responses are attached to the task as a read-only record afterwards. *For example, a hardware selection form for a new hire can dynamically show eligible models based on their job type, and trigger a workflow that assigns a device from the inventory.* See [journey tasks](/sections/documentation/journeys/tasks) and [native forms](/sections/documentation/forms/overview). ### Rank knowledge articles by audience You can now tune how Serval ranks your knowledge when the help desk agent searches it. In the Ranking tab of the Manage knowledge sources dialog, add rules that boost articles for a specific audience, or when an article's properties match, and set each rule's strength to Slight, Normal, or Strong. Ranking rules only reorder results, so a boosted article rises for the people it's meant for without ever hiding anything from anyone else. *For example, boost Sales Commission articles for the Sales team so their requests surface those first, while everyone else's results stay unchanged.* See [Ranking rules](/sections/documentation/knowledge-base/overview#ranking-rules). ### Trigger workflows from ticket feedback and agent replies Two new events can trigger a workflow: one when a requester submits feedback on a ticket, and one when the help desk agent posts a reply. *For example, a low feedback score on a resolved ticket can open a follow-up ticket for the team lead.* ### Connect Box folders and ingest Office files from Google Drive You can now connect a Box folder as a knowledge source, and Google Drive ingestion now reads Microsoft Word (.docx) and Excel (.xlsx) files alongside the formats it already handled. See [Connected sources](/sections/documentation/knowledge-base/connected-sources). *** ## Access management **Use team assignment rules to route provisioning tasks** Manual provisioning gains an Unassigned option, so you can create a provisioning task without naming an assignee up front. The task is then routed by your team's ticket assignment rules. See [Access provisioning](/sections/access-management/configuration/access-provisioning). ## Ticketing **Narrow the assignee picker to your team** When a team turns on Restrict assignment to team members only, the assignee picker now offers only that team's members, so a ticket can't be assigned outside the team by accident. ## Campaigns **Know when an email campaign will span several days** When you run an email campaign whose audience is larger than your daily email quota, the run dialog now tells you the send will spread across several days before you start it. This applies to both immediate and scheduled runs. See [Campaign scheduling](/sections/documentation/campaigns/scheduling). ## Workflows **Restore recently deleted workflows** Deleting a workflow is no longer permanent. A new *Recently deleted* area in team settings keeps deleted workflows for 30 days, and a restored workflow comes back as an unpublished draft so you can review it before pushing it live again. Restoring is available to people who can delete workflows. See [Team settings](/sections/documentation/platform/team-settings). ## Databases **Record-level access rules for databases** You can now control who sees an individual database record, not just a whole table. Open a record and choose Manage access to this record to limit it to specific people or groups. Anyone not included sees a *Restricted record* placeholder on the row, and managing these rules is limited to people with permission to manage record access. See [Database record access](/sections/documentation/databases/administration#record-level-access-rules). ## Platform **A Restricted base role for custom roles** Custom roles can now start from a new Restricted base role, giving you a tighter starting point when building a role from scratch. **Delegate major-incident controls through custom roles** The ability to declare and promote a major incident can now be granted through a custom role, so you can hand out exactly that control without broader permissions. **API keys can last up to a year** When you create a public API key, you can now set its expiration up to one year out. **Reactivate deactivated users in bulk** On the users list, you can now select multiple deactivated users and reactivate them together. See [Permissions](/sections/documentation/platform/permissions). ## Integrations **New integrations** Serval adds native integrations for [Zscaler ZDX](/sections/integrations/zscaler-zdx) and [Netskope](/sections/integrations/netskope) (Beta). **Exclude guest accounts from Microsoft user sync** When Serval syncs users from Microsoft Entra through Microsoft Graph, you can now leave guest accounts out. Turn on Exclude guest accounts on the user sync configuration, and external or partner accounts stop flowing into Serval as users, so your synced directory stays limited to full employees. **Control whether tickets show in Slack Home** A new Show tickets in Slack Home setting controls whether a team's open tickets appear in people's Slack Home, without affecting approvals, quick actions, or notification delivery. See [Slack](/sections/integrations/slack). ## For developers **Public API additions** The public API gains new endpoints to manage dashboards, work with ticket priorities, and update or delete ticket labels. # September 18, 2026 Source: https://docs.serval.com/sections/release-notes/Sep-18-2026 Import access grants from a screenshot, author overnight SLA schedules, build richer assignment and SLA conditions, and launch a journey from a catalog request. ## Highlights * [Import access grants from a screenshot](#import-access-grants-from-a-screenshot) * [Overnight and split-shift coverage in SLA schedules](#overnight-and-split-shift-coverage-in-sla-schedules) * [Richer assignment and SLA conditions](#richer-assignment-and-sla-conditions) ### Import access grants from a screenshot When you import an application's access grants into Serval, you can now hand over a screenshot instead of a CSV. Drop in a PNG, JPEG, or WebP image of the app's members list, and Serval reads each row and turns it into a grant you can review, map, and confirm before anything is imported. ### Overnight and split-shift coverage in SLA schedules A schedule's weekly hours can now hold more than one time range per day, and a range is allowed to end at midnight. That makes overnight and split-shift coverage possible: chain a range that ends at midnight on one day with one that starts at midnight on the next, or give a single day a morning and an afternoon window with a gap between them. *For example, model overnight support by pairing an 11:00 PM to midnight range with a midnight to 6:00 AM range on the following day.* See [Schedules](/sections/documentation/ticketing/ticket-configuration/schedules). ### Richer assignment and SLA conditions Assignment rules and SLA conditions can now match on several values at once and offer more ways to compare them. A condition can match any of several labels, statuses, or requester groups, check whether a label is present, exclude a set of categories, and requester text conditions are typed as free text rather than picked from a fixed list. *For example, write one SLA that applies whenever a ticket carries any of several labels, or an assignment rule that skips a group of categories.* See [SLAs](/sections/documentation/ticketing/ticket-configuration/slas) and [assignment rules](/sections/documentation/ticketing/ticket-configuration/assignment). *** ## Ticketing **Show several visibility groups in one list** A ticket list can now be narrowed to more than one visibility group at a time, so you can watch related queues together instead of switching between them. **Search connected tickets by their ServiceNow number** The ticket search boxes now match a connected ticket by its ServiceNow number, so you can jump straight to a ticket using the identifier your team already knows it by. ## Knowledge **Restore or delete an archived knowledge base** The Archive view now lets you restore or permanently delete a whole knowledge base, not just its individual pages. ## Workflows **Authenticate workflow webhooks with a bearer token** A workflow's incoming webhook trigger can now require a bearer token, giving you a standard way to authenticate the systems that call it. **Embed database file images in workflow emails** Workflow emails can now display images stored on database records inline, so a message can show a picture from your data rather than only linking to it. ## Journeys **Start a journey from a service catalog request** A service catalog submission can now launch a journey directly, instead of only opening a ticket. ## Integrations **New integrations** Serval adds four native integrations in beta: [BeyondTrust Password Safe](/sections/integrations/beyondtrust-password-safe), [BeyondTrust Privileged Remote Access](/sections/integrations/beyondtrust-pra), [Omnissa Workspace ONE UEM](/sections/integrations/omnissa-workspace-one-uem), and [HCL BigFix](/sections/integrations/bigfix). **Choose Jira permission scopes at connect time** The Jira connection flow now shows a permission picker, the same one Confluence uses, so a connection requests only the scopes it needs. Bring-your-own Atlassian apps no longer have to mirror a fixed, full scope list. ## For developers **Public API additions** The public API gains endpoints to create, read, update, and delete ticket statuses with portable IDs, configure a team's help desk channels, search a user's access memberships, submit ticket feedback, read attachment descriptions, and set a message's created-at time. The create-ticket SDK helper can now also attach a workflow to the ticket it creates. # September 25, 2026 Source: https://docs.serval.com/sections/release-notes/Sep-25-2026 Choose which ticket types a team uses, reclassify a ticket, see who can and can't read a knowledge document, and CC an external participant on a ticket. ## Highlights * [Manage which ticket types a team uses](#manage-which-ticket-types-a-team-uses) * [Reclassify a ticket between a request and an incident](#reclassify-a-ticket-between-a-request-and-an-incident) * [See who can and can't read a knowledge document](#see-who-can-and-cant-read-a-knowledge-document) * [CC an external participant on a ticket](#cc-an-external-participant-on-a-ticket) ### Manage which ticket types a team uses Every team can now choose which ticket types are enabled. In a team's ticket type settings, turn a type on or off, and Serval only offers and files the types you keep enabled across manual creation, the public API, and reclassification. This capability is now available to all teams. *For example, a team that never handles incidents can turn Incident off so its queue only ever fills with the request types it owns.* See [Ticket types](/sections/documentation/ticketing/ticket-configuration/ticket-types). ### Reclassify a ticket between a request and an incident When a ticket arrives as the wrong type, an agent can now convert it in place instead of closing it and opening a new one. Reclassifying moves a ticket between a request and an incident from the ticket's actions menu, keeping its history, comments, and status, and it is available through the public API so workflows can reclassify too. ### See who can and can't read a knowledge document For knowledge sources that sync their own permissions, the Manage knowledge sources list now shows a Permissions column that explains, for each document, who can see it and who can't. Open a document's permissions to review the audience Serval resolved from the source's own access rules. *For example, a ServiceNow knowledge article synced with its ACLs shows which groups can read it, so you can confirm the help desk agent only surfaces it to the right people.* See [Knowledge base](/sections/documentation/knowledge-base/overview). ### CC an external participant on a ticket Any agent who can reply to a ticket can now CC an external email address on it. Add the address in the composer, and Serval subscribes it as a guest and includes it on the reply email, the same way it handles an unknown sender arriving over email. *** ## Ticketing **Turn ticket deletion off for a team** A team can now disable ticket deletion entirely, so tickets can't be moved to trash or permanently deleted while the setting is off. See [Resolving tickets](/sections/documentation/ticketing/resolving-tickets). **Unlink tickets** Linked tickets can now be unlinked from the ticket side panel. A control on each linked ticket removes the link in both directions and records the change on both tickets' timelines. **Follow up in the requester's local time zone** Follow-up schedules can now gate requester reminders by the requester's own local hours, so a reminder lands during their working day rather than the team's. See [Schedules](/sections/documentation/ticketing/ticket-configuration/schedules). **Restrict assignment to an assignment group** A new team setting keeps a ticket that carries an assignment group assignable only to that group's members, so it can't be handed to someone outside the group by accident. See [Assignment](/sections/documentation/ticketing/ticket-configuration/assignment). ## Email **Show the sending inbox and address on a ticket** A ticket now shows which inbox and address a reply is sent from, so it's clear which mailbox is corresponding with the requester. **Trust an org member's email from any domain** Email intake can now trust an authenticated org member whose address is on a domain the team can't allowlist. When the setting is on, a message that passes DKIM or DMARC from an active member or admin is trusted even though its domain isn't listed, while unknown senders still fall back to the allowlist. ## Embedded chat widget **Read and unread conversations, responder identity, and a default team** The embedded chat widget now marks conversations read and unread, shows who replied, and lets you set the team a new request opens on. ## Forms **Show a submitted form's attachment on the ticket** When a form submission includes a file, that attachment now appears on the ticket alongside the submitted values. See [Forms](/sections/documentation/forms/overview). ## Databases **Point item-reference fields at more than one table** An item-reference field can now target multiple tables, so a record can link to items across several databases from a single field. See [Schema design](/sections/documentation/databases/schema-design). **Narrow table and field access to roles, groups, and people** Access to a database table or field can now be scoped to specific roles, groups, and people within a team, not just broad audiences. See [Database administration](/sections/documentation/databases/administration). ## Workflows **Advertise and gate cross-team workflows** A team can now choose which of its integrations it advertises to other teams and configure the approval procedure that runs when another team requests a run. See [Team settings](/sections/documentation/platform/team-settings). ## Platform **See a user's permissions on their detail page** A user's detail page now has a Permissions tab that lays out what that user can do, so you can check someone's effective access without piecing it together from their roles and groups. ## Integrations **Answer Jira follow-up comments with the help desk agent** When a ticket is synced to Jira, the help desk agent now answers follow-up comments posted on the Jira issue, not just the first message, so a requester can keep the conversation going from Jira and get replies back on the issue. See [Jira](/sections/integrations/jira). **Trust a private CA on a custom HTTP connection** A custom HTTP connection can now carry its own CA certificate, so Serval can reach an internal endpoint whose certificate is signed by a private authority. **Fetch a custom integration's API docs from a URL** A custom integration can now fetch its API documentation from a URL instead of uploading a spec, so its tools are described from a single source you maintain and can be refreshed when that source changes. **Connect multiple ServiceNow accounts on one instance** A single ServiceNow instance can now hold more than one connected account, so different capabilities can authenticate as different service accounts. See [ServiceNow](/sections/integrations/servicenow). ## For developers **Public API and SDK additions** The public API and SDK gain endpoints to list a team's email intake configurations and read a ticket's feedback attachments. Creating a ticket status now requires its ticket type and returns a portable status ID, workflow-authored ticket messages can be backdated and attributed, a created ticket can be backdated, and workflow actions can download a credentialed binary file. # Release Notes Source: https://docs.serval.com/sections/release-notes/index Stay up to date with the latest features, improvements, and fixes in Serval. Welcome to Serval's release notes. Here you'll find details about new features, improvements, and bug fixes in each release. ## Recent Releases * [October 2, 2026](/sections/release-notes/Oct-02-2026) * [September 25, 2026](/sections/release-notes/Sep-25-2026) * [September 18, 2026](/sections/release-notes/Sep-18-2026) * [September 11, 2026](/sections/release-notes/Sep-11-2026) * [September 4, 2026](/sections/release-notes/Sep-04-2026) * [August 28, 2026](/sections/release-notes/Aug-28-2026) * [August 21, 2026](/sections/release-notes/Aug-21-2026) * [August 14, 2026](/sections/release-notes/Aug-14-2026) * [August 7, 2026](/sections/release-notes/Aug-07-2026) * [July 31, 2026](/sections/release-notes/Jul-31-2026) * [July 24, 2026](/sections/release-notes/Jul-24-2026) * [July 17, 2026](/sections/release-notes/Jul-17-2026) * [July 10, 2026](/sections/release-notes/Jul-10-2026) * [July 3, 2026](/sections/release-notes/Jul-03-2026) * [June 26, 2026](/sections/release-notes/Jun-26-2026) * [June 19, 2026](/sections/release-notes/Jun-19-2026) * [June 12, 2026](/sections/release-notes/Jun-12-2026) * [June 5, 2026](/sections/release-notes/Jun-05-2026) * [May 27, 2026](/sections/release-notes/May-27-2026) * [May 20, 2026](/sections/release-notes/May-20-2026) * [May 13, 2026](/sections/release-notes/May-13-2026) * [April 22, 2026](/sections/release-notes/Apr-22-2026) * [April 9, 2026](/sections/release-notes/Apr-9-2026) * [April 1, 2026](/sections/release-notes/Apr-1-2026) * [March 26, 2026](/sections/release-notes/Mar-26-2026) * [March 12, 2026](/sections/release-notes/Mar-12-2026) * [March 6, 2026](/sections/release-notes/Mar-6-2026) * [February 26, 2026](/sections/release-notes/Feb-26-2026) * [February 12, 2026](/sections/release-notes/Feb-12-2026) * [February 5, 2026](/sections/release-notes/Feb-5-2026) * [January 21, 2026](/sections/release-notes/Jan-21-2026) * [January 15, 2026](/sections/release-notes/Jan-15-2026) * [January 8, 2026](/sections/release-notes/Jan-8-2026) * [December 17, 2025](/sections/release-notes/Dec-17-2025) * [December 10, 2025](/sections/release-notes/Dec-10-2025) * [December 4, 2025](/sections/release-notes/Dec-4-2025) * [November 26, 2025](/sections/release-notes/Nov-26-2025) * [November 18, 2025](/sections/release-notes/Nov-18-2025) * [November 10, 2025](/sections/release-notes/Nov-10-2025) # Bring Your Own Cloud (BYOC) on AWS Source: https://docs.serval.com/sections/self-hosting/byoc-aws Run the full Serval application single-tenant in an AWS account you own, operated by your team or by Serval # Bring Your Own Cloud (BYOC) on AWS In this delivery model, **you bring an AWS account you own** and the full Serval application runs single-tenant inside it. The application runtime and all customer data remain in that account, and your AWS credentials never leave your environment. The deployment is operated either by your own team (**self-managed**) or by Serval (**Serval-managed**). Fully self-hosted and single-tenant. The application runtime and customer data live only in your AWS account. You choose whether your team operates the deployment or Serval operates it for you; the deployment is the same in both cases. ## Operating the deployment The operator — your team in self-managed, or Serval in Serval-managed — is responsible for: * Infrastructure provisioning for the supported self-hosted stack inside your AWS account * Application installation and upgrades * Baseline monitoring and operational work * Applying each new Serval release inside the AWS account ## How it works ```mermaid theme={null} flowchart LR Serval["Serval"] -->|"publishes versioned release"| Release["Versioned release"] Release --> Operator["Operator
(your team or Serval)"] Operator -->|"applies in your account"| Resources["Your AWS resources
(VPC, EKS, databases, Serval app)"] ``` * **Versioned releases.** Serval publishes each new version as a versioned release. * **Applied in your account.** The operator applies the release inside your AWS account; your AWS credentials never leave your environment. * **Onboarding.** Serval provides the deployment definition, a configuration reference, and setup scripts during onboarding. ## Self-managed deployments If your team operates the deployment, Serval provides a **deployment bundle** — Terraform intended for AWS, along with Kubernetes/Helm configuration and setup scripts — that stands up the full stack. It builds on standard AWS services, including: * **Amazon EKS** — the Kubernetes platform * **Amazon Aurora (PostgreSQL)** — application databases * **Amazon ElastiCache** and **Amazon OpenSearch** — cache and search * **Amazon S3** — object storage * **AWS Secrets Manager** — application secrets **Align with the provided configuration as much as possible.** Serval ships a standard bundle of Terraform, Kubernetes/Helm, and setup scripts, and can walk your team through applying it in a dedicated setup session. The deployment is designed, tested, and supported against that standard configuration. You **can** point the deployment at your own external services — your own PostgreSQL, Redis, Temporal, OpenSearch, or S3-compatible object storage — instead of the ones the bundle provisions, and Serval supports doing so. But **every deviation from the provided configuration adds operational lift on your side and makes upgrades harder to apply cleanly**, because your deployment diverges from the tested baseline. Align with the provided configuration entirely, or as much as possible, to minimize unexpected behavior and keep upgrades simple. ## What you own * The AWS account and any required internal approvals * DNS and domain ownership * AI provider keys and any customer-owned credentials supplied during onboarding * Environment-specific policies, guardrails, and access reviews * Whether your team or Serval operates the deployment * Any networking you need to reach private internal systems (see [Private Network Access](/sections/self-hosting/private-network-access)) ## When to choose this model Choose BYOC on AWS when you: * Want the application runtime and data single-tenant in an AWS account you own * Are standardizing on AWS for the Serval deployment ## Next steps Review the AWS account, DNS, and AI provider requirements before onboarding. See how BYOC on AWS compares with Hybrid Self-Hosted. Start the onboarding process. # Prerequisites — BYOC on AWS Source: https://docs.serval.com/sections/self-hosting/byoc-aws-prerequisites What you need to provide before deploying a fully self-hosted Serval stack in your AWS account # Prerequisites — BYOC on AWS Complete the following before onboarding for the **BYOC on AWS** delivery model. Most prerequisites are common to both operating modes; a few differ depending on whether your team operates the deployment (self-managed) or Serval does (Serval-managed) — see [BYOC on AWS](/sections/self-hosting/byoc-aws). ## AWS account * A **dedicated AWS account** that you own, used only for Serval. It can be a member account in your existing AWS Organization. * **Administrator access** to that account for whoever applies the deployment, at initial setup and for each release upgrade. This delivery model is single-tenant. The AWS account should be dedicated to the Serval deployment and not shared with unrelated production workloads. ## Domain and DNS * A domain you own with the ability to create DNS records * DNS records for: * `app.` — the Serval web application * `*.api.` — backend API services (subdomain-based ingress) ## Private network access (optional) If the deployment needs to reach resources on your internal network — on-prem Active Directory, internal LDAP, self-hosted Git, internal APIs — plan the connectivity path before onboarding. See [Private Network Access](/sections/self-hosting/private-network-access) for the common AWS patterns (Site-to-Site VPN, Direct Connect, Transit Gateway, private DNS resolution). ## LLM / agent API keys Provide your own keys for the AI providers Serval uses at runtime: * **Anthropic API key** — primary provider for AI agents and help desk functionality * **OpenAI API key** — used for embeddings, image description, and specific model tasks These keys are installed into the deployment during onboarding and never leave your environment. ## Additional prerequisites by operating mode * **Self-managed** — administrator access to the account during setup, and a team able to apply and operate the deployment (working familiarity with Terraform and AWS). Serval provides the deployment bundle and setup scripts; see [Self-managed deployments](/sections/self-hosting/byoc-aws#self-managed-deployments). * **Serval-managed** — the internal approvals needed for Serval to operate the deployment in your account. ## Onboarding phases 1. Prepare the AWS account and access 2. Provision and deploy the stack 3. Configure core integrations (Slack, AI keys, OAuth apps) 4. Account setup (teams, users, workflows) ## Next steps Understand the operating modes and what runs in your account. Kick off onboarding. # Hybrid Self-Hosted Source: https://docs.serval.com/sections/self-hosting/hybrid Run workflows in your infrastructure while Serval operates the cloud backend. Configure worker-local credentials to keep integration secrets out of Serval Cloud. # Hybrid Self-Hosted In the Hybrid delivery model, you run the **Serval worker and its credential proxy** inside your own infrastructure. Serval operates the backend application services, control plane, web app, and application database in Serval Cloud. Workflows routed to your hybrid worker execute there, and its proxy can reach resources on your private network. Local integration credentials require separate configuration. Installing a hybrid worker or enabling **Run on self-hosted workers** doesn't move credentials out of Serval Cloud. For connections that must keep the real credential in your cluster, register a placeholder in Serval and follow [Worker-Local Integration Credentials](/sections/self-hosting/deployment/worker-local-integrations) to mount and verify the real credential. ## Why teams pick Hybrid * **Smallest footprint** of the self-hosting options. * **Fastest to stand up**: Usually hours, not days. * **Local integration credentials**: Configure selected connections with [worker-local credentials](/sections/self-hosting/deployment/worker-local-integrations) mounted in your cluster instead of storing the real secrets in Serval Cloud. Connections you do not configure this way are stored encrypted in Serval Cloud, exactly as in the standard SaaS deployment. * **Reach private systems**: The worker can talk to on-prem Active Directory, self-hosted GitLab, internal APIs, and internal databases without opening them to the public internet. See [Private Network Access](/sections/self-hosting/private-network-access). * **Minimal ops burden**: Serval owns operations for the backend and control plane. Your team owns the worker host. ## What runs where | Component | Where it runs | Who operates it | | - | - | - | | **Serval worker** | A Linux host you provide | You (host and OS); Serval (the worker process itself, via auto-update) | | **Backend application services** | Serval Cloud | Serval | | **Web application** | Serval Cloud | Serval | | **Application database** (users, workflows, tickets, knowledge base) | Serval Cloud | Serval | | **Workflow code execution** for self-hosted-routed runs | Your worker | You operate the host; Serval supplies the worker software | | **Local credential injection** | Your worker's proxy | You configure the mounted Secret | | **Integration credentials** | Your worker's mounted Secret when configured locally; otherwise stored encrypted in Serval Cloud | You choose the credential configuration | Serval Cloud orchestrates runs and stores workflow definitions and run history. **Run on self-hosted workers** routes workflows using that integration to your worker; other workflows continue to run on Serval-managed workers. See the [workflow and credential flow diagram](/sections/self-hosting/deployment/hybrid-setup#how-a-workflow-uses-local-credentials). ## Where your data lives * **Application data**: Users, tickets, workflow definitions, run history, and knowledge base content live in Serval Cloud. If you need application data in your own environment, pick [BYOC on AWS](/sections/self-hosting/byoc-aws) instead. * **Integration credentials**: Credentials entered in the Serval dashboard are stored encrypted in Serval Cloud. For a connection set to run on the worker, the worker's proxy fetches the credential from Serval Cloud at call time, injects it into the request, and sends that request to the target service from inside your network, so the target system is never exposed to the internet. For a locally configured connection, the proxy loads the mounted credential instead and Serval Cloud holds only a placeholder. In both cases the credential reaches the target service, such as Okta, and never reaches workflow code. Worker-local credentials support API keys, OAuth client credentials, and custom auth data; they do not support user-authorized (three-legged) OAuth, and they apply only to workflow and ingestion runs the worker executes, not to features Serval Cloud calls directly, such as ticket channels and ticket sync. * **Payloads returned from integration calls**: Responses return to the workflow running on your worker. Run results and application data can flow back to Serval Cloud. If those payloads must also stay inside your network, pick [BYOC on AWS](/sections/self-hosting/byoc-aws). ## Prerequisites * **A dedicated, always-on Linux host** you control (x86\_64). A VM or container host is fine; bare metal is fine. * **Recommended: 4 vCPU, 16 GB RAM, 40 GB free disk.** Minimum: 2 vCPU, 8 GB RAM, 20 GB free disk. * **A dedicated-CPU instance.** Avoid burstable/credit-based types, which throttle CPU under sustained load and can make the worker slow or unreliable. * **Outbound HTTPS** from the worker host to the Serval Cloud control plane (`public.api.serval.com`) and Docker Hub, where the Hybrid worker Helm chart is published. * **Network access** from the worker host to every internal system you want Serval to reach — AD, internal GitLab, internal APIs, internal databases. See [Private Network Access](/sections/self-hosting/private-network-access) for specifics. * **Ability to run an install command** on the host (the exact commands are in our [password-protected deployment docs](/sections/self-hosting/request-access)). ## Existing Kubernetes clusters If your platform team already operates Kubernetes workloads, you can usually run the Hybrid worker as a standard workload in that environment instead of provisioning a dedicated VM with k3s. The worker is packaged as a Helm chart, and k3s is the lightweight default path documented for teams that want the smallest single-host installation. The advanced install steps for existing clusters are in the password-protected [Hybrid Worker Setup](/sections/self-hosting/deployment/hybrid-setup) guide. Serval shares that guide during onboarding so your platform team can review the exact Helm values, credentials flow, and network policy settings before deployment. ### FAQ Yes. If your EKS cluster can reach Serval Cloud and the private systems you want Serval to automate against, the worker can run there as a Helm-managed Kubernetes workload. This is often a good fit for teams that already have AWS networking, cluster security, image-pull controls, and upgrade processes in place. No. k3s is the default documented path for a simple dedicated Linux host because it provides a small Kubernetes runtime with minimal setup. The worker itself is deployed with Helm and does not require k3s specifically. Yes, for standard Kubernetes clusters that meet the worker's requirements. During onboarding, Serval will confirm the target cluster, Kubernetes version, outbound egress, Docker Hub access, namespace/RBAC model, and any cloud-specific settings such as AWS IAM Roles for Service Accounts (IRSA). Run the worker in its own namespace, restrict who can read its Kubernetes secrets, and give the pod only the service account permissions it needs. The worker needs outbound HTTPS to Serval Cloud and Docker Hub, DNS resolution, and egress to the private hosts and ports it will call. If you enforce Kubernetes NetworkPolicies, make sure the cluster CNI supports them and allow the required egress paths. Customers with access can start with [Hybrid Worker Setup](/sections/self-hosting/deployment/hybrid-setup). That guide covers the pre-flight checks, generated install command, Helm deployment, optional flags, verification, upgrades, and troubleshooting. If you are evaluating Hybrid, request access through [Deployment instructions](/sections/self-hosting/request-access) and mention that you want to deploy into an existing EKS or Kubernetes cluster. ## When to choose Hybrid vs. fully self-hosted | You care most about... | Pick... | | - | - | | Smallest setup and fastest time-to-value | **Hybrid** | | Keeping integration credentials out of Serval Cloud | **Hybrid with worker-local credentials configured** (also possible with BYOC on AWS) | | Serval automating against resources on your private network | **Hybrid** (also possible with BYOC on AWS) | | Keeping **all application data** — users, tickets, knowledge — in your own environment | [BYOC on AWS](/sections/self-hosting/byoc-aws) | | Not running anything in your own infrastructure | Serval Cloud (not self-hosted) | ## Next steps See Hybrid side-by-side with BYOC on AWS. How the worker reaches resources on your internal network. Worker install, configuration, and operations — shared with customers during onboarding. Start a Hybrid deployment. # Self-Hosting Options Source: https://docs.serval.com/sections/self-hosting/index Compare the two Serval self-hosting delivery models — Hybrid and BYOC on AWS — and learn how to get access to deployment instructions. # Self-Hosting Options Serval supports two delivery models when you run it in your own infrastructure. The two axes that actually differ between them are (1) **what you bring** — a Linux host, or an AWS account — and (2) **who operates it** — Serval, your team, or (for the full application) either, your choice. Pick the model that matches both. This page is the starting point for evaluation; step-by-step deployment instructions are [shared with customers](/sections/self-hosting/request-access) during onboarding. Most organizations should start with **Hybrid Self-Hosted** (smallest footprint, fastest setup). Choose **BYOC on AWS** when regulatory or data-residency requirements demand that the entire application runs in your environment. ## The two delivery models You run only the Serval **worker** in your infrastructure. Serval operates the backend in Serval Cloud. The worker reaches your private systems, and credentials for them can be kept in your cluster with worker-local credentials. Smallest footprint, fastest to set up. The **full Serval application** runs single-tenant in an AWS account you own, operated by your team or by Serval — your choice. Your AWS credentials never leave your environment. ## Comparison | | Hybrid Self-Hosted | BYOC on AWS | | - | - | - | | **What you bring** | A Linux host for the worker | A supported AWS account you own | | **Who operates it** | Serval (backend) + your team (worker host) | Your choice — your team or Serval | | **What runs in your environment** | Worker only | Full application stack | | **Where app data lives** | Serval cloud | Your AWS account | | **Tenancy** | Shared control plane, isolated worker | Single-tenant | | **Upgrades** | Automatic | Applied in your account, by your chosen operator | | **Setup time** | Hours | Days (onboarding) | | **Kubernetes expertise required** | Basic | Minimal if Serval-managed; working knowledge if self-managed | ## Does Serval need to reach private resources? If Serval needs to talk to systems on your internal network — on-prem Active Directory, internal LDAP, self-hosted GitLab, internal APIs, etc. — the connectivity story differs per model. The [Private Network Access](/sections/self-hosting/private-network-access) page walks through the options for each. ## Evaluating Serval self-hosting Use these pages while you decide which model fits: How Hybrid works, what runs where, prerequisites, and when to pick it over the fully self-hosted option. The operating modes (self-managed or Serval-managed) and what your team supplies either way. The AWS account, DNS, and AI provider requirements before onboarding. Options for letting Serval reach resources on your internal network (on-prem AD, internal GitLab, etc.). ## Ready to deploy? Detailed installation steps, configuration references, integration setup, and operational runbooks live in a password-protected area of this site, which we share with customers and teams working through onboarding. Installation, configuration, integration setup, and day-2 operations for Serval self-hosting. # Private Network Access Source: https://docs.serval.com/sections/self-hosting/private-network-access How Serval reaches systems on your internal network — on-prem Active Directory, internal LDAP, self-hosted GitLab, internal APIs — under each delivery model. # Private Network Access Many Serval deployments need to talk to systems that only live inside a customer's private network: on-prem Active Directory, internal LDAP, self-hosted GitLab or Bitbucket Server, internal HR or ticketing APIs, internal databases for lookups, and so on. The path Serval takes to reach those systems depends on which [self-hosting delivery model](/sections/self-hosting/index) you pick. Pick your delivery model first on [Self-Hosting Options](/sections/self-hosting/index). Private network access is a downstream consideration, but it can tip you toward one model over another if the targets are hard to expose to AWS or to Serval Cloud. ## Hybrid Self-Hosted **Easiest for most private integrations.** The Serval worker runs on a Linux host you provide, inside your network. It reaches private resources using normal internal networking — whatever DNS, VPN, Direct Connect, ExpressRoute, or MPLS your infrastructure already uses. * Install the worker on a host that can resolve and reach your private targets. * Credentials for the private service can be kept in your cluster with [worker-local credentials](/sections/self-hosting/deployment/worker-local-integrations); otherwise they are stored encrypted in Serval Cloud and the worker's proxy fetches them at call time. * If the worker host already sits on the same network as the target (for example, inside your corporate VPN CIDR, or in an AD-joined subnet), there is usually no extra networking to do. Common pattern: put the worker on an internal VM that's already trusted by your internal systems, and Serval integrations "just work" against those systems. ## BYOC on AWS The Serval application runs inside an AWS account you own, so connectivity from Serval to your private networks is a standard AWS networking problem — the same one you solve for any workload running in that account. Common patterns: * **AWS Site-to-Site VPN** between the Serval VPC and your on-prem network. * **AWS Direct Connect** for dedicated, high-throughput circuits. * **VPC peering** or **Transit Gateway** to a hub VPC that already has on-prem connectivity. * **Route 53 private hosted zones** or a DNS forwarder for resolving internal hostnames (for example, your AD domain). * **Security group + NACL** changes to allow the Serval subnets to reach specific target IPs/ports. Onboarding decision points: * Which VPC/subnets should the Serval stack deploy into? * Which of the connectivity patterns above already exists and which needs to be stood up? * Does on-prem DNS need to resolve from the Serval VPC? Work these out with Serval during onboarding; the stack deploys into the VPC and subnets you specify, applied by your chosen operator — your team or Serval. ## Common private targets In customer environments we regularly wire up: * **On-prem Active Directory / LDAP** — identity, group sync, user lookups * **Self-hosted GitLab or Bitbucket Server** — code and workflow automation * **Internal service APIs behind a corporate firewall** — custom automations * **Internal PostgreSQL/MySQL** — data lookups and enrichment * **SCIM endpoints on private networks** — user provisioning ## Questions to answer before onboarding When you talk to your Serval deployment team, have rough answers ready to: * Which private targets does Serval need to reach, and at what hostnames/ports? * **DNS** — does Serval need to resolve internal hostnames? Which zones? * **Auth** — does the target use Kerberos, LDAP+TLS, mTLS, a private PKI, or just TLS with a public CA? * **Throughput and latency** — are these interactive lookups, bulk syncs, or streaming? * **Change control** — who owns the VPN/Direct Connect/firewall changes on your side? ## See also * [Network Security and Firewalls](/sections/administration/network-security-and-firewalls) — egress, firewall, and allowlist configuration for deploying Serval in your organization. *** ## Next steps Pick the delivery model first, then come back here for connectivity. How the fully self-hosted delivery model works. # Deployment instructions Source: https://docs.serval.com/sections/self-hosting/request-access Customer documentation for deploying, operating, and configuring Serval self-hosting. # Deployment instructions Installation, configuration, integration setup, and day-2 operations for Serval self-hosting live in a password-protected area of this site. We share the password with customers and teams working with us through onboarding. Everything you need to **evaluate** Serval self-hosting is on this site — the [Hybrid Self-Hosted overview](/sections/self-hosting/hybrid), the [BYOC on AWS overview](/sections/self-hosting/byoc-aws) and its [prerequisites](/sections/self-hosting/byoc-aws-prerequisites), and [private network access options](/sections/self-hosting/private-network-access). ## Getting access * **Existing customers:** reach out to your Serval contact — your account executive, solutions engineer, or shared Slack Connect channel. * **Evaluating Serval:** email [support@serval.com](mailto:support@serval.com) or reach out at [serval.com/contact](https://serval.com/contact), and mention that you're evaluating a self-hosted deployment. ## Deployment docs (password required) Once you have the password, these are the main landing pages: Start here — the deployment model picker and prerequisites. Deploy the Hybrid worker on a Linux host or into an existing Kubernetes cluster. Full backend service inventory, ingress host scheme, database layout. Teams, users, integration connections, and the initial setup checklist. Per-integration OAuth app registration, credentials, redirect URIs. Production checklist, security, monitoring, upgrades, maintenance. `values.yaml` reference for infrastructure and application settings.