Skip to main content

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.

πŸ“‹ Prerequisites:
  • 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​

  1. Download our SSL certificate chain (link)
  2. Import the certificate to the Windows Certificate Store on your integration server
  3. Add the certificate to Trusted Root Certification Authorities
  4. Ensure the certificate is properly validated for HTTPS connections

Step 2: Configure ServiceNow OAuth 2.0 Application​

  1. Navigate to System OAuth > Application Registry in ServiceNow
  2. 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)
  3. Configure OAuth Scopes:
    • useraccount
    • read
    • write

Step 3: Configure ServiceNow User Permissions​

Ensure your integration user has the following roles:

  1. ITIL Role: For incident and request management
  2. REST API Access: For API connectivity
  3. 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​

  1. Go to the "Integrations" section in your Docflo.ai platform
  2. Create an API key for ServiceNow integration
  3. Copy the API key and store it securely
  4. 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:

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

  2. Service Request Table Custom Fields:

    • Same custom fields as above

ServiceNow User Role Configuration​

Ensure your integration user has the following roles:

  1. itil: ITIL role for incident and request management
  2. rest_api_explorer: REST API access
  3. web_service_admin: Web service administration
  4. 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:

  1. Install the service using sc create or InstallUtil
  2. Configure service account with appropriate permissions
  3. Set up logging for monitoring and troubleshooting
  4. Schedule regular document polling

Option 2: Azure Function​

Deploy as an Azure Function for cloud-based processing:

  1. Create Azure Function App
  2. Configure timer trigger for scheduled execution
  3. Set application settings for configuration values
  4. Monitor execution through Azure portal

Option 3: Scheduled Task​

Use Windows Task Scheduler for periodic execution:

  1. Create a scheduled task to run the application
  2. Set appropriate triggers (hourly, daily, etc.)
  3. Configure security context for ServiceNow access
  4. 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​

  1. 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
  2. SSL Certificate Issues:

    • Verify certificate installation in Windows Certificate Store
    • Check certificate chain completeness
    • Ensure proper certificate binding
  3. API Rate Limiting:

    • ServiceNow has API rate limits per user/instance
    • Implement retry logic with exponential backoff
    • Monitor API usage through ServiceNow stats
  4. 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
  5. 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
  6. 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