ServiceNow
This guide walks you through the steps required to connect Docflo.ai to your ServiceNow instance, enabling seamless document integration and automated incident/request processing.
- ServiceNow instance with REST API access
- Visual Studio or development environment for .NET
- Docflo.ai account with API access
- ServiceNow user with appropriate roles and permissions
- SSL certificate management capabilities
- ServiceNow OAuth 2.0 or Basic Authentication setup
π Integration Stepsβ
Follow these steps to establish a secure connection between Docflo.ai and your ServiceNow instance:
Step 1: Import SSL Certificate Chainβ
- Download our SSL certificate chain (link)
- Import the certificate to the Windows Certificate Store on your integration server
- Add the certificate to Trusted Root Certification Authorities
- Ensure the certificate is properly validated for HTTPS connections
Step 2: Configure ServiceNow OAuth 2.0 Applicationβ
- Navigate to System OAuth > Application Registry in ServiceNow
- Create a new OAuth API endpoint for external clients:
- Name: Docflo Integration
- Client ID: (auto-generated, note this down)
- Client Secret: (auto-generated, note this down)
- Redirect URL:
https://your-integration-server/callback - Refresh Token Lifespan: 7776000 (90 days)
- Access Token Lifespan: 1800 (30 minutes)
- Configure OAuth Scopes:
- useraccount
- read
- write
Step 3: Configure ServiceNow User Permissionsβ
Ensure your integration user has the following roles:
- ITIL Role: For incident and request management
- REST API Access: For API connectivity
- Table Access:
- incident: Create, Read, Write
- sc_request: Create, Read, Write
- sc_req_item: Create, Read, Write
- sys_attachment: Create, Read
- sys_user: Read
Step 4: Generate API Credentialsβ
- Go to the "Integrations" section in your Docflo.ai platform
- Create an API key for ServiceNow integration
- Copy the API key and store it securely
- Copy the tenant ID as well - you'll need both for the integration
Step 5: Create ServiceNow Integration Serviceβ
Create a Windows Service or scheduled application using ServiceNow's REST API with OAuth 2.0. Here's a sample C# implementation:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Net.Http.Headers;
using System.Linq;
namespace DocfloServiceNowIntegration
{
public class DocfloServiceNowIntegrationService
{
private readonly string _docfloApiUrl;
private readonly string _tenantId;
private readonly string _apiKey;
private readonly string _serviceNowInstanceUrl;
private readonly string _clientId;
private readonly string _clientSecret;
private readonly string _username;
private readonly string _password;
private readonly HttpClient _httpClient;
private readonly HttpClient _serviceNowClient;
private string _accessToken;
private DateTime _tokenExpiry;
public DocfloServiceNowIntegrationService(string docfloApiUrl, string tenantId, string apiKey,
string serviceNowInstanceUrl, string clientId, string clientSecret,
string username, string password)
{
_docfloApiUrl = docfloApiUrl;
_tenantId = tenantId;
_apiKey = apiKey;
_serviceNowInstanceUrl = serviceNowInstanceUrl;
_clientId = clientId;
_clientSecret = clientSecret;
_username = username;
_password = password;
// Initialize Docflo HTTP client
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Add("x-tenant-id", _tenantId);
_httpClient.DefaultRequestHeaders.Add("apiKey", _apiKey);
// Initialize ServiceNow HTTP client
_serviceNowClient = new HttpClient();
_serviceNowClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<bool> AuthenticateWithServiceNow()
{
try
{
var authUrl = $"{_serviceNowInstanceUrl}/oauth_token.do";
var authData = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("client_id", _clientId),
new KeyValuePair<string, string>("client_secret", _clientSecret),
new KeyValuePair<string, string>("username", _username),
new KeyValuePair<string, string>("password", _password)
};
var content = new FormUrlEncodedContent(authData);
var response = await _serviceNowClient.PostAsync(authUrl, content);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var authResponse = JsonConvert.DeserializeObject<ServiceNowAuthResponse>(responseContent);
_accessToken = authResponse.AccessToken;
_tokenExpiry = DateTime.UtcNow.AddSeconds(authResponse.ExpiresIn - 60); // 1 minute buffer
// Set authorization header for future requests
_serviceNowClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", _accessToken);
Console.WriteLine("Successfully authenticated with ServiceNow");
return true;
}
else
{
var errorContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"ServiceNow authentication failed: {response.StatusCode}");
Console.WriteLine($"Error details: {errorContent}");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception during ServiceNow authentication: {ex.Message}");
return false;
}
}
private async Task<bool> EnsureValidToken()
{
if (string.IsNullOrEmpty(_accessToken) || DateTime.UtcNow >= _tokenExpiry)
{
return await AuthenticateWithServiceNow();
}
return true;
}
public async Task<List<DocfloDocument>> GetDocfloDocuments(string documentType, bool includeResults = true)
{
try
{
string url = $"{_docfloApiUrl}/docs/v1/document?type={documentType}&includeResults={includeResults}";
HttpResponseMessage response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
string jsonContent = await response.Content.ReadAsStringAsync();
var docfloResponse = JsonConvert.DeserializeObject<DocfloResponse>(jsonContent);
return docfloResponse.Data;
}
catch (Exception ex)
{
Console.WriteLine($"Error fetching Docflo documents: {ex.Message}");
return new List<DocfloDocument>();
}
}
public async Task<bool> CreateIncident(DocfloDocument document)
{
try
{
if (!await EnsureValidToken())
{
Console.WriteLine("Failed to authenticate with ServiceNow");
return false;
}
// Extract data from Docflo document results
var extractedData = ExtractIncidentData(document);
// Create incident payload for ServiceNow
var incidentPayload = new
{
short_description = extractedData.ShortDescription ?? $"Incident from Docflo document {document.Id}",
description = extractedData.Description ?? $"Incident created from Docflo document processing. Document ID: {document.Id}, Source: {document.SourceDesc}",
caller_id = await GetOrCreateUser(extractedData.CallerEmail, extractedData.CallerName),
category = extractedData.Category ?? "Software",
subcategory = extractedData.Subcategory ?? "Application",
priority = MapPriority(extractedData.Priority),
urgency = MapUrgency(extractedData.Urgency),
state = "1", // New
assignment_group = await GetAssignmentGroup(extractedData.AssignmentGroup),
// Custom fields for Docflo tracking
u_docflo_document_id = document.Id,
u_docflo_source_id = document.SourceId,
u_docflo_created_date = document.CreatedAt
};
string jsonPayload = JsonConvert.SerializeObject(incidentPayload, Formatting.Indented);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
string serviceNowUrl = $"{_serviceNowInstanceUrl}/api/now/table/incident";
HttpResponseMessage response = await _serviceNowClient.PostAsync(serviceNowUrl, content);
if (response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();
var createResponse = JsonConvert.DeserializeObject<ServiceNowCreateResponse>(responseContent);
Console.WriteLine($"Incident created successfully for document {document.Id}");
Console.WriteLine($"ServiceNow Incident Number: {createResponse.Result.Number}");
// Attach the original document if available
await AttachDocumentToRecord("incident", createResponse.Result.SysId, document);
return true;
}
else
{
string errorContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Error creating Incident: {response.StatusCode}");
Console.WriteLine($"Error details: {errorContent}");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception creating Incident: {ex.Message}");
return false;
}
}
public async Task<bool> CreateServiceRequest(DocfloDocument document)
{
try
{
if (!await EnsureValidToken())
{
Console.WriteLine("Failed to authenticate with ServiceNow");
return false;
}
// Extract data from Docflo document results
var extractedData = ExtractRequestData(document);
// Create service request payload for ServiceNow
var requestPayload = new
{
short_description = extractedData.ShortDescription ?? $"Service Request from Docflo document {document.Id}",
description = extractedData.Description ?? $"Service request created from Docflo document processing. Document ID: {document.Id}, Source: {document.SourceDesc}",
requested_for = await GetOrCreateUser(extractedData.RequestedForEmail, extractedData.RequestedForName),
opened_by = await GetOrCreateUser(extractedData.OpenedByEmail, extractedData.OpenedByName),
priority = MapPriority(extractedData.Priority),
urgency = MapUrgency(extractedData.Urgency),
state = "1", // Open
assignment_group = await GetAssignmentGroup(extractedData.AssignmentGroup),
// Custom fields for Docflo tracking
u_docflo_document_id = document.Id,
u_docflo_source_id = document.SourceId,
u_docflo_created_date = document.CreatedAt
};
string jsonPayload = JsonConvert.SerializeObject(requestPayload, Formatting.Indented);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
string serviceNowUrl = $"{_serviceNowInstanceUrl}/api/now/table/sc_request";
HttpResponseMessage response = await _serviceNowClient.PostAsync(serviceNowUrl, content);
if (response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();
var createResponse = JsonConvert.DeserializeObject<ServiceNowCreateResponse>(responseContent);
Console.WriteLine($"Service Request created successfully for document {document.Id}");
Console.WriteLine($"ServiceNow Request Number: {createResponse.Result.Number}");
// Attach the original document if available
await AttachDocumentToRecord("sc_request", createResponse.Result.SysId, document);
return true;
}
else
{
string errorContent = await response.Content.ReadAsStringAsync();
Console.WriteLine($"Error creating Service Request: {response.StatusCode}");
Console.WriteLine($"Error details: {errorContent}");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception creating Service Request: {ex.Message}");
return false;
}
}
public async Task<string> GetOrCreateUser(string email, string name)
{
try
{
if (string.IsNullOrEmpty(email) && string.IsNullOrEmpty(name))
{
return ""; // Return empty if no user info provided
}
// First, try to find existing user by email
string searchUrl = $"{_serviceNowInstanceUrl}/api/now/table/sys_user";
if (!string.IsNullOrEmpty(email))
{
searchUrl += $"?sysparm_query=email={Uri.EscapeDataString(email)}";
}
else if (!string.IsNullOrEmpty(name))
{
searchUrl += $"?sysparm_query=name={Uri.EscapeDataString(name)}";
}
HttpResponseMessage searchResponse = await _serviceNowClient.GetAsync(searchUrl);
if (searchResponse.IsSuccessStatusCode)
{
string searchContent = await searchResponse.Content.ReadAsStringAsync();
var searchResult = JsonConvert.DeserializeObject<ServiceNowQueryResponse<ServiceNowUser>>(searchContent);
if (searchResult.Result?.Any() == true)
{
return searchResult.Result.First().SysId;
}
}
// User not found, create new one (if your ServiceNow instance allows it)
var userPayload = new
{
user_name = email ?? GenerateUsername(name),
email = email ?? "",
first_name = ExtractFirstName(name),
last_name = ExtractLastName(name),
active = true
};
string jsonPayload = JsonConvert.SerializeObject(userPayload, Formatting.Indented);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
string createUrl = $"{_serviceNowInstanceUrl}/api/now/table/sys_user";
HttpResponseMessage createResponse = await _serviceNowClient.PostAsync(createUrl, content);
if (createResponse.IsSuccessStatusCode)
{
string createContent = await createResponse.Content.ReadAsStringAsync();
var createResult = JsonConvert.DeserializeObject<ServiceNowCreateResponse>(createContent);
Console.WriteLine($"User created: {userPayload.user_name}");
return createResult.Result.SysId;
}
else
{
Console.WriteLine($"Could not create user, using empty user reference");
return "";
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception in GetOrCreateUser: {ex.Message}");
return "";
}
}
public async Task<string> GetAssignmentGroup(string groupName)
{
try
{
if (string.IsNullOrEmpty(groupName))
{
return ""; // Return empty if no group specified
}
string searchUrl = $"{_serviceNowInstanceUrl}/api/now/table/sys_user_group?sysparm_query=name={Uri.EscapeDataString(groupName)}";
HttpResponseMessage searchResponse = await _serviceNowClient.GetAsync(searchUrl);
if (searchResponse.IsSuccessStatusCode)
{
string searchContent = await searchResponse.Content.ReadAsStringAsync();
var searchResult = JsonConvert.DeserializeObject<ServiceNowQueryResponse<ServiceNowGroup>>(searchContent);
if (searchResult.Result?.Any() == true)
{
return searchResult.Result.First().SysId;
}
}
Console.WriteLine($"Assignment group '{groupName}' not found");
return "";
}
catch (Exception ex)
{
Console.WriteLine($"Exception in GetAssignmentGroup: {ex.Message}");
return "";
}
}
public async Task<bool> AttachDocumentToRecord(string tableName, string recordSysId, DocfloDocument document)
{
try
{
// This is a simplified example - you would need to get the actual document content
// from Docflo or have it available in your system
var attachmentPayload = new
{
table_name = tableName,
table_sys_id = recordSysId,
file_name = $"docflo_document_{document.Id}.pdf",
content_type = "application/pdf"
};
string jsonPayload = JsonConvert.SerializeObject(attachmentPayload, Formatting.Indented);
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
string attachUrl = $"{_serviceNowInstanceUrl}/api/now/attachment/file";
HttpResponseMessage response = await _serviceNowClient.PostAsync(attachUrl, content);
if (response.IsSuccessStatusCode)
{
Console.WriteLine($"Document attached successfully to {tableName} record");
return true;
}
else
{
Console.WriteLine($"Failed to attach document: {response.StatusCode}");
return false;
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception attaching document: {ex.Message}");
return false;
}
}
private string MapPriority(string priority)
{
// Map priority values to ServiceNow priority numbers
switch (priority?.ToLower())
{
case "critical":
case "1":
return "1"; // Critical
case "high":
case "2":
return "2"; // High
case "moderate":
case "medium":
case "3":
return "3"; // Moderate
case "low":
case "4":
return "4"; // Low
case "planning":
case "5":
return "5"; // Planning
default:
return "3"; // Default to Moderate
}
}
private string MapUrgency(string urgency)
{
// Map urgency values to ServiceNow urgency numbers
switch (urgency?.ToLower())
{
case "high":
case "1":
return "1"; // High
case "medium":
case "2":
return "2"; // Medium
case "low":
case "3":
return "3"; // Low
default:
return "2"; // Default to Medium
}
}
private string GenerateUsername(string name)
{
if (string.IsNullOrEmpty(name))
return "user" + DateTime.Now.Ticks.ToString().Substring(0, 6);
return name.Replace(" ", ".").ToLower();
}
private string ExtractFirstName(string fullName)
{
if (string.IsNullOrEmpty(fullName))
return "";
var parts = fullName.Split(' ');
return parts.Length > 0 ? parts[0] : "";
}
private string ExtractLastName(string fullName)
{
if (string.IsNullOrEmpty(fullName))
return "";
var parts = fullName.Split(' ');
return parts.Length > 1 ? string.Join(" ", parts.Skip(1)) : "";
}
private ServiceNowIncidentData ExtractIncidentData(DocfloDocument document)
{
var data = new ServiceNowIncidentData();
// Extract data from Docflo results
if (document.DocfloResults?.ModelFields?.Items?.Value != null)
{
foreach (var item in document.DocfloResults.ModelFields.Items.Value)
{
var description = item.ValueObject?.Description;
if (description != null)
{
switch (description.Type?.ToLower())
{
case "short_description":
case "title":
case "subject":
data.ShortDescription = description.ValueString;
break;
case "description":
case "details":
case "issue_description":
data.Description = description.ValueString;
break;
case "caller_email":
case "reporter_email":
data.CallerEmail = description.ValueString;
break;
case "caller_name":
case "reporter_name":
data.CallerName = description.ValueString;
break;
case "category":
data.Category = description.ValueString;
break;
case "subcategory":
data.Subcategory = description.ValueString;
break;
case "priority":
data.Priority = description.ValueString;
break;
case "urgency":
data.Urgency = description.ValueString;
break;
case "assignment_group":
data.AssignmentGroup = description.ValueString;
break;
}
}
}
}
return data;
}
private ServiceNowRequestData ExtractRequestData(DocfloDocument document)
{
var data = new ServiceNowRequestData();
// Extract data from Docflo results
if (document.DocfloResults?.ModelFields?.Items?.Value != null)
{
foreach (var item in document.DocfloResults.ModelFields.Items.Value)
{
var description = item.ValueObject?.Description;
if (description != null)
{
switch (description.Type?.ToLower())
{
case "short_description":
case "title":
case "subject":
data.ShortDescription = description.ValueString;
break;
case "description":
case "details":
case "request_description":
data.Description = description.ValueString;
break;
case "requested_for_email":
data.RequestedForEmail = description.ValueString;
break;
case "requested_for_name":
data.RequestedForName = description.ValueString;
break;
case "opened_by_email":
data.OpenedByEmail = description.ValueString;
break;
case "opened_by_name":
data.OpenedByName = description.ValueString;
break;
case "priority":
data.Priority = description.ValueString;
break;
case "urgency":
data.Urgency = description.ValueString;
break;
case "assignment_group":
data.AssignmentGroup = description.ValueString;
break;
}
}
}
}
return data;
}
public void Dispose()
{
_httpClient?.Dispose();
_serviceNowClient?.Dispose();
}
}
// Data models
public class DocfloResponse
{
[JsonProperty("data")]
public List<DocfloDocument> Data { get; set; }
}
public class DocfloDocument
{
[JsonProperty("_id")]
public string Id { get; set; }
[JsonProperty("sourceId")]
public string SourceId { get; set; }
[JsonProperty("sourceDesc")]
public string SourceDesc { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("numOfPages")]
public string NumOfPages { get; set; }
[JsonProperty("createdAt")]
public string CreatedAt { get; set; }
[JsonProperty("docflo_results")]
public DocfloResults DocfloResults { get; set; }
}
public class DocfloResults
{
[JsonProperty("modelFields")]
public ModelFields ModelFields { get; set; }
}
public class ModelFields
{
[JsonProperty("Items")]
public ItemsField Items { get; set; }
}
public class ItemsField
{
[JsonProperty("value")]
public List<Item> Value { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
}
public class Item
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("valueObject")]
public ValueObject ValueObject { get; set; }
}
public class ValueObject
{
[JsonProperty("Description")]
public Description Description { get; set; }
}
public class Description
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("valueString")]
public string ValueString { get; set; }
[JsonProperty("content")]
public string Content { get; set; }
}
public class ServiceNowAuthResponse
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
}
public class ServiceNowCreateResponse
{
[JsonProperty("result")]
public ServiceNowRecord Result { get; set; }
}
public class ServiceNowRecord
{
[JsonProperty("sys_id")]
public string SysId { get; set; }
[JsonProperty("number")]
public string Number { get; set; }
}
public class ServiceNowQueryResponse<T>
{
[JsonProperty("result")]
public List<T> Result { get; set; }
}
public class ServiceNowUser
{
[JsonProperty("sys_id")]
public string SysId { get; set; }
[JsonProperty("user_name")]
public string UserName { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
}
public class ServiceNowGroup
{
[JsonProperty("sys_id")]
public string SysId { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
}
public class ServiceNowIncidentData
{
public string ShortDescription { get; set; }
public string Description { get; set; }
public string CallerEmail { get; set; }
public string CallerName { get; set; }
public string Category { get; set; }
public string Subcategory { get; set; }
public string Priority { get; set; }
public string Urgency { get; set; }
public string AssignmentGroup { get; set; }
}
public class ServiceNowRequestData
{
public string ShortDescription { get; set; }
public string Description { get; set; }
public string RequestedForEmail { get; set; }
public string RequestedForName { get; set; }
public string OpenedByEmail { get; set; }
public string OpenedByName { get; set; }
public string Priority { get; set; }
public string Urgency { get; set; }
public string AssignmentGroup { get; set; }
}
// Main program example
class Program
{
static async Task Main(string[] args)
{
var service = new DocfloServiceNowIntegrationService(
"https://api.docflo.ai", // Replace with actual Docflo API URL
"your-tenant-id", // Replace with your tenant ID
"your-api-key", // Replace with your API key
"https://your-instance.service-now.com", // Replace with your ServiceNow instance URL
"your-client-id", // Replace with OAuth Client ID
"your-client-secret", // Replace with OAuth Client Secret
"your-servicenow-username", // Replace with ServiceNow username
"your-servicenow-password" // Replace with ServiceNow password
);
try
{
// Authenticate with ServiceNow
bool authenticated = await service.AuthenticateWithServiceNow();
if (authenticated)
{
// Get documents from Docflo
var documents = await service.GetDocfloDocuments("incident_report", true);
foreach (var document in documents)
{
// Process each document based on status
if (document.Status == "processed")
{
// Create Incident for incident reports
bool incidentResult = await service.CreateIncident(document);
// Or create Service Request for service requests
// bool requestResult = await service.CreateServiceRequest(document);
if (incidentResult)
{
Console.WriteLine($"Successfully created incident for document {document.Id}");
}
}
}
}
else
{
Console.WriteLine("Failed to authenticate with ServiceNow");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error in main process: {ex.Message}");
}
finally
{
service.Dispose();
}
}
}
}
π§ Configuration Requirementsβ
NuGet Packages Requiredβ
Add these NuGet packages to your project:
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
ServiceNow Custom Fields Setupβ
Create custom fields in ServiceNow for tracking Docflo documents:
-
Incident Table Custom Fields:
-
Field Name:
u_docflo_document_id -
Type: String
-
Label: Docflo Document ID
-
Max Length: 50
-
Field Name:
u_docflo_source_id -
Type: String
-
Label: Docflo Source ID
-
Max Length: 50
-
Field Name:
u_docflo_created_date -
Type: String
-
Label: Docflo Created Date
-
Max Length: 50
-
-
Service Request Table Custom Fields:
- Same custom fields as above
ServiceNow User Role Configurationβ
Ensure your integration user has the following roles:
- itil: ITIL role for incident and request management
- rest_api_explorer: REST API access
- web_service_admin: Web service administration
- import_admin: For data import operations
Application Configurationβ
Create an app.config file with your settings:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="DocfloApiUrl" value="https://api.docflo.ai" />
<add key="TenantId" value="your-tenant-id" />
<add key="ApiKey" value="your-api-key" />
<add key="ServiceNowInstanceUrl" value="https://your-instance.service-now.com" />
<add key="ServiceNowClientId" value="your-client-id" />
<add key="ServiceNowClientSecret" value="your-client-secret" />
<add key="ServiceNowUsername" value="your-servicenow-username" />
<add key="ServiceNowPassword" value="your-servicenow-password" />
</appSettings>
</configuration>
π Deployment Optionsβ
Option 1: Windows Serviceβ
Deploy as a Windows Service for continuous processing:
- Install the service using
sc createor InstallUtil - Configure service account with appropriate permissions
- Set up logging for monitoring and troubleshooting
- Schedule regular document polling
Option 2: Azure Functionβ
Deploy as an Azure Function for cloud-based processing:
- Create Azure Function App
- Configure timer trigger for scheduled execution
- Set application settings for configuration values
- Monitor execution through Azure portal
Option 3: Scheduled Taskβ
Use Windows Task Scheduler for periodic execution:
- Create a scheduled task to run the application
- Set appropriate triggers (hourly, daily, etc.)
- Configure security context for ServiceNow access
- Monitor execution logs
π Monitoring and Loggingβ
Implement comprehensive logging using NLog or Serilog:
// Add to your service class
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
public void LogIntegrationActivity(string message, Exception ex = null)
{
if (ex == null)
{
logger.Info(message);
}
else
{
logger.Error(ex, message);
}
}
π ServiceNow Specific Considerationsβ
OAuth 2.0 Authenticationβ
ServiceNow supports OAuth 2.0 for secure API access:
- Client ID/Secret: From Application Registry
- Grant Type: Password or Authorization Code
- Token Refresh: Automatic token refresh handling
- Scopes: Configure appropriate scopes for API access
Table API Structureβ
ServiceNow uses table-based REST API:
- Base URL:
https://instance.service-now.com/api/now/table/ - incident: Incident management
- sc_request: Service request management
- sys_user: User management
- sys_user_group: Group management
Priority and Urgency Mappingβ
ServiceNow uses numeric values for priority and urgency:
- Priority: 1 (Critical), 2 (High), 3 (Moderate), 4 (Low), 5 (Planning)
- Urgency: 1 (High), 2 (Medium), 3 (Low)
- Impact: 1 (High), 2 (Medium), 3 (Low)
State Managementβ
ServiceNow records have state fields:
- Incident States: 1 (New), 2 (In Progress), 6 (Resolved), 7 (Closed)
- Request States: 1 (Open), 2 (Work in Progress), 3 (Closed Complete), 4 (Closed Incomplete)
π Integration Complete! Your ServiceNow instance is now connected to Docflo.ai and can automatically create incidents and service requests from processed documents, enabling seamless ITSM workflow automation.
π Troubleshootingβ
Common Issuesβ
-
OAuth Authentication Errors:
- Verify Client ID and Client Secret from Application Registry
- Check username and password credentials
- Ensure user has appropriate roles and permissions
- Verify OAuth scopes are configured correctly
-
SSL Certificate Issues:
- Verify certificate installation in Windows Certificate Store
- Check certificate chain completeness
- Ensure proper certificate binding
-
API Rate Limiting:
- ServiceNow has API rate limits per user/instance
- Implement retry logic with exponential backoff
- Monitor API usage through ServiceNow stats
-
Data Mapping Issues:
- Validate extracted data from Docflo documents
- Check required fields for ServiceNow record creation
- Ensure proper data type conversions
- Verify field names match ServiceNow schema
-
User/Group Resolution Issues:
- Verify users exist in ServiceNow sys_user table
- Check assignment groups exist and are active
- Ensure proper user permissions for record creation
-
Custom Field Issues:
- Verify custom fields exist in ServiceNow
- Check field names match exactly (case-sensitive)
- Ensure fields are enabled for the record types
- Verify user has access to custom fields
π Supportβ
For technical assistance with the ServiceNow integration:
- Contact Docflo.ai support team
- Consult ServiceNow Developer documentation
- Review ServiceNow REST API guides
- Contact your ServiceNow administrator
- Visit ServiceNow Community for additional resources