---
title: "How to Migrate from SysAid to ServiceNow: The Complete ITSM Guide"
slug: how-to-migrate-from-sysaid-to-servicenow-the-complete-itsm-guide
date: 2026-07-17
author: Roopi
categories: [Migration Guide, SysAid ITSM, ServiceNow]
excerpt: "Complete technical guide to SysAid to ServiceNow migration. Covers object mapping, API limits, CMDB migration, Import Set batching, and step-by-step process."
tldr: SysAid to ServiceNow migration requires splitting unified Service Records into separate ITSM tables while respecting API limits and semaphore queues. Expect 3 to 6 weeks.
canonical: https://clonepartner.com/blog/how-to-migrate-from-sysaid-to-servicenow-the-complete-itsm-guide/
---

# How to Migrate from SysAid to ServiceNow: The Complete ITSM Guide


A **SysAid to ServiceNow migration** is a complex, multi-phase data engineering project that requires splitting SysAid's unified Service Record entity into ServiceNow's distinct Incident, Request Item, Change Request, and Problem tables. The realistic timeline for a mid-size enterprise (50,000 to 200,000 records) is 3 to 6 weeks. The single biggest risk is broken relationships: CMDB CI links, parent-child ticket references, and activity history threads that do not survive a naive CSV export.

> [!NOTE]
> **Quick answer:** SysAid stores Incidents, Requests, Changes, and Problems in a single Service Record entity, while ServiceNow requires each type in its own table. Workflow rules, custom fields, and CMDB relationships do not transfer 1-to-1. Teams with fewer than 10,000 records and no CMDB data can manage a CSV-based migration in-house. Anything above that, or with compliance requirements, benefits from a managed migration service. The biggest design risk is routing SysAid Requests to the wrong ServiceNow table and then breaking assignee, CI, and fulfillment relationships.

## Why Enterprise IT Teams Move from SysAid to ServiceNow

The most common drivers are scale, platform extensibility, and enterprise integration requirements. SysAid serves mid-market IT teams well, but organizations that outgrow its customization ceiling or need deep integrations with SAP, Workday, or Azure DevOps typically move to ServiceNow.

Three platform-specific reasons come up repeatedly:

- **Workflow complexity limits.** SysAid's workflow automation is template-driven. ServiceNow's Flow Designer and Business Rules engine supports multi-step, conditional, approval-chain workflows natively, including parallel approval paths, SLA-triggered escalations, and cross-table orchestration.
- **CMDB depth.** SysAid's CMDB supports CI types, sub-types, and relation types with up to 250 customizable fields per CI type. ServiceNow's CMDB (built on the Common Service Data Model) supports hundreds of CI classes with inheritance, discovery integrations via MID Server and Discovery patterns, and service mapping out of the box.
- **Enterprise ecosystem.** ServiceNow's IntegrationHub, MID Servers, and scoped application model provide integration depth — including bidirectional connectors for SAP, Workday, Jira, Azure DevOps, and Splunk — that SysAid's Workato-embedded marketplace does not match at scale.

For a deeper comparison of these two platforms, see our [ServiceNow vs SysAid architecture guide](https://clonepartner.com/blog/blog/servicenow-vs-sysaid-architecture-tco-migration-guide/).

## What Are the Architectural Differences Between SysAid and ServiceNow?

The core architectural difference that makes this migration non-trivial is SysAid's unified Service Record model versus ServiceNow's multi-table model.

<cite index="46-6">In SysAid, users create service record forms to record an Incident, Change, Problem, or Request and submit them for resolution.</cite> All four record types live in the same entity, differentiated by a `type` field. <cite index="21-4">The API gives you access to the following SysAid entities: service records, assets, CIs, and users.</cite> You access all of them through the same `/api/v1/sr` endpoint, filtering by type.

ServiceNow stores each ITSM process in its own table:

- **Incidents** in `incident`
- **Requests** in `sc_request`, with line items in `sc_req_item` (Requested Items, commonly abbreviated as RITMs)
- **Change Requests** in `change_request`
- **Problems** in `problem`

Every SysAid Service Record must be classified, split, and routed to the correct ServiceNow table during transformation. A record with `type=incident` maps to `incident`. A record with `type=change` maps to `change_request`. The tricky one is Requests.

ServiceNow generates a request and discrete requested items when a catalog item is ordered. ([servicenow.com](https://www.servicenow.com/docs/r/servicenow-platform/service-catalog/c_RequestingAServiceCatalogItem.html)) If a SysAid Request truly represents catalog fulfillment, it should decompose into an `sc_request` parent and one or more `sc_req_item` children. But many SysAid Requests are generic help desk asks with no real catalog model behind them. For those, many teams map them to `incident` or a custom task table instead. That decision belongs in design, not in UAT. If you do not decide up front which SysAid Requests become real Service Catalog requests in ServiceNow, you will either create fake RITMs or lose fulfillment reporting.

The second major difference is relationship modeling. SysAid links CIs to Service Records and assets to CIs in a flat relational structure. ServiceNow uses a hierarchical CMDB with class inheritance (e.g., `cmdb_ci_server` extends `cmdb_ci_hardware` extends `cmdb_ci`), and relationships are stored in `cmdb_rel_ci` with typed relationship records. Migrating SysAid's CI relationships requires mapping each SysAid CI relation type to a ServiceNow `cmdb_rel_type` record. ServiceNow's CMDB imports are designed to respect identification and reconciliation rules via the IRE (Identification and Reconciliation Engine), so raw CI inserts are a common way to create duplicates. ([servicenow.com](https://www.servicenow.com/docs/r/servicenow-platform/configuration-management-database-cmdb/c_CMDBIdentifyandReconcile.html))

### SysAid Cloud vs. On-Premise: Extraction Differences

SysAid is available as both a Cloud (SaaS) and On-Premise deployment. The extraction approach differs significantly:

- **SysAid Cloud** — API-only extraction. You are limited to the REST API (`/api/v1/`) and Connect API (`/connect/v1/`) endpoints, with the rate limits described below. No direct database access is available.
- **SysAid On-Premise** — In addition to the API, on-premise deployments may allow direct SQL access to the underlying database (typically Microsoft SQL Server or MySQL). Direct DB queries can bypass API rate limits and extract data significantly faster, but require coordination with the DBA team and carry risk if the internal schema is undocumented. SysAid also offers report-based CSV exports from the admin console, which can supplement API extraction for simpler datasets (users, assets, flat ticket lists) but do not capture relationships, activities, or attachments.

The rest of this guide assumes API-based extraction, which applies to both editions. If you have on-premise DB access, you can use direct SQL queries to accelerate the extraction phase, but all transformation and loading guidance still applies.

## SysAid to ServiceNow Object and Field Mapping

Map your data model before touching any APIs. The mapping table below covers the core ITSM objects.

| SysAid Object | ServiceNow Table | Notes |
|---|---|---|
| Service Record (type=incident) | `incident` | Map SysAid `id` to a custom `u_sysaid_id` field for traceability |
| Service Record (type=request) | `sc_request` + `sc_req_item` OR `incident` | Only use `sc_request` + `sc_req_item` when the record represents catalog fulfillment. Generic help desk requests often map better to `incident` or a custom task table |
| Service Record (type=change) | `change_request` | SysAid change types (standard, normal, emergency) must map to ServiceNow's `type` field values |
| Service Record (type=problem) | `problem` | Map to `problem`, not `problem_task`. SysAid problems may have linked incidents; rebuild these as `task_rel_task` records |
| Users (Agents) | `sys_user` | Map SysAid `admin` flag and group memberships to ServiceNow roles (`itil`, `itil_admin`) |
| Users (End Users) | `sys_user` | Set `active=true` and appropriate `user_name`. No role assignment needed |
| Companies | `core_company` | SysAid stores company at the user level. ServiceNow has a dedicated company table. Load before users |
| Assets | `alm_asset` | SysAid assets and CIs are separate objects. Decide whether each source asset is a business asset, a CI, or both in ServiceNow |
| CIs | `cmdb_ci_*` (class-specific) | SysAid CI types must map to the correct ServiceNow CI class. Use IRE or `CMDBTransformUtil` to enforce identification during import |
| CI Relationships | `cmdb_rel_ci` | Each SysAid CI relation type maps to a `cmdb_rel_type` record. "Installed on" and "Depends on" must be mapped individually |
| Activities / Notes | `sys_journal_entry` | SysAid activities become journal entries on the target record. Preserve timestamps and author attribution |
| Attachments | `sys_attachment` + `sys_attachment_doc` | SysAid attachments are linked by Service Record ID. Each must be re-uploaded to the correct ServiceNow table and `table_sys_id` |

### Field-Level Mapping Considerations

- **Picklist values.** SysAid uses numeric IDs for status, priority, urgency, and impact fields. ServiceNow uses different numeric scales. SysAid priority "1" (highest) may not map to ServiceNow priority "1" (Critical) without an explicit enum crosswalk. Both systems can expose account-specific labels and automation behind these fields, so validate against your actual tenant data. ([developers.sysaid.com](https://developers.sysaid.com/reference/service-records))
- **Custom fields.** SysAid custom fields are prefixed with `cust_` in the API response. In ServiceNow, custom fields on ITSM tables use the `u_` prefix. Every custom field requires a matching field creation in ServiceNow before import. Custom fields are not discoverable by guesswork — SysAid requires a separate custom field metadata pull, and list-type custom fields can return indexed values that must be translated through the metadata map before you can load human-readable values or ServiceNow choice values. ([developers.sysaid.com](https://developers.sysaid.com/docs/custom-fields))
- **Date and time formats.** <cite index="1-5">SysAid's API uses ISO 8601 (UTC) format, for example `2024-06-10T14:32:00Z`.</cite> However, some SysAid Service Record fields such as `closeTime` are described as UNIX format (epoch milliseconds) in the API reference. Validate real payloads from your tenant before writing transforms for created, updated, and closed timestamps. ServiceNow stores datetimes in UTC internally but displays them in the user's configured timezone; ensure your transforms output UTC strings in `YYYY-MM-DD HH:mm:ss` format for ServiceNow import. ([developers.sysaid.com](https://developers.sysaid.com/docs/api-standards-conventions))
- **HTML vs. plain text.** SysAid description and solution fields can contain HTML. ServiceNow journal fields accept HTML, but rendering depends on the UI policy. Strip or sanitize HTML during transformation to avoid broken formatting in the activity stream. Specifically, remove inline `<style>` blocks, embedded `<img>` tags referencing SysAid-hosted URLs, and any JavaScript fragments.
- **Reference fields.** Reference fields in ServiceNow require the exact `sys_id` of the related record. You must maintain a translation database (mapping SysAid `id` → ServiceNow `sys_id`) during the migration. Every reference field — `caller_id`, `assigned_to`, `cmdb_ci`, `company`, `assignment_group` — must be resolved through this crosswalk.

### What Has No Clean Equivalent in ServiceNow?

- **SysAid "Journey" tab.** <cite index="46-3">The Journey tab is an actionable audit log of all Service Record Events.</cite> ServiceNow has no direct equivalent. The closest option is to import journey entries as journal entries (preserving timestamps) or as records in a custom audit table. Some teams create a custom `u_sysaid_journey` table to preserve the full event stream.
- **SysAid templates.** SysAid uses templates as predefined formats for creating service records. ServiceNow uses catalog items, record producers, and form views instead. Templates must be rebuilt manually — there is no automated conversion path.
- **SysAid one-step automations and workflow rules.** These cannot be exported via API. They must be audited manually in the SysAid admin console and recreated as ServiceNow Business Rules, Flow Designer flows, or Scheduled Jobs. Document each rule's trigger condition, action, and scope before attempting recreation.
- **SLA elapsed-time counters.** SysAid SLA counters (elapsed time, breach timestamps) are calculated fields. ServiceNow has its own SLA engine (`task_sla`). Historical SLA data can be imported as custom fields for reporting, but the ServiceNow SLA engine will not retroactively calculate SLAs for imported records. For compliance reporting, store original SysAid SLA outcomes (met/breached, elapsed time, breach timestamp) as `u_` fields on the migrated ticket.
- **Contextual attachment placement.** SysAid supports contextual attachments inside rich text fields. ServiceNow attachment loading is file-oriented. The files can migrate, but their exact inline placement within a description or note will not transfer. ([documentation.sysaid.com](https://documentation.sysaid.com/docs/view-attachments))

## How to Extract Data from SysAid: API Limits and Pagination

SysAid exposes its data through two API generations: the legacy REST API (`/api/v1/`) and the newer Connect API (`/connect/v1/`). For bulk extraction, the legacy REST API is more commonly used because it supports broader entity access.

### Rate Limits

<cite index="3-5">The following request limits apply when using SysAid's REST API: a maximum of two API login requests will be allowed within a five-minute period. Up to 1,000 other API requests will be allowed within a five-minute period. If usage exceeds the framework, an HTTP 429 message appears, and you will be able to continue once that five-minute time period has passed.</cite>

At 1,000 requests per 5 minutes, you have a sustained ceiling of roughly 200 requests per minute (3.33 requests per second). The API also exposes `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers for pacing. Build your extraction scripts to read these headers and back off before hitting the wall. ([developers.sysaid.com](https://developers.sysaid.com/docs/api-standards-conventions))

### Pagination

<cite index="1-1,1-2">SysAid APIs implement offset-based pagination using two key parameters: `limit` (optional, default 20, max 500) and `offset` (optional, used to calculate the starting point for the page of results).</cite>

Always set `limit=500` to minimize the number of API calls on list endpoints. For a dataset of 100,000 service records, you will need 200 paginated requests, consuming 200 of your 1,000-request budget per 5-minute window.

The Connect API's service record search endpoint (`/connect/v1/service-records/search`) has a narrower limit of 100 rows per call, while companies, assets, CIs, and activities support up to 500 rows per call with offset pagination. ([developers.sysaid.com](https://developers.sysaid.com/reference/searchservicerecords))

### Authentication

<cite index="21-12,21-13">Upon a successful login, the API consumer needs to retrieve the JSESSIONID cookie from the Response Header and submit it in all subsequent API Request Headers. For security reasons, each session expires after 24 hours.</cite> Build session refresh logic into your extraction scripts to handle long-running exports. The Connect API uses a two-step client credentials flow (OAuth 2.0) instead, which is generally more robust for automated extraction. ([developers.sysaid.com](https://developers.sysaid.com/docs/authentication-guide))

### Key Extraction Endpoints

| Data Type | Endpoint | Notes |
|---|---|---|
| Service Records | `GET /api/v1/sr?type={incident\|request\|change\|problem}` | Filter by type to pre-sort records |
| Users | `GET /api/v1/users` | Returns agents and end users |
| Assets | `GET /api/v1/assets` | Hardware and software assets |
| CIs | `GET /api/v1/ci` | CMDB configuration items |
| Activities | `GET /connect/v1/activities/sr/search` | Activity history per Service Record |
| Related Items | `GET /connect/v1/service-records/{recordId}/related-items` | Linked records |
| Attachments | `GET /api/v1/sr/{id}/attachment` | Returns metadata. Binary download requires a separate call per attachment |
| Custom Field Metadata | `GET /api/v1/sr/custom-fields` | Required for translating list-type custom field indexed values to human-readable labels |

> [!WARNING]
> SysAid's API does not support bulk export of attachments in a single call. Each attachment must be downloaded individually. For a dataset with 50,000 attachments, this alone consumes 50,000 API requests — roughly 250 minutes (4+ hours) of extraction time at the rate limit ceiling. Test attachment export on day 1 and factor this into your timeline.

### Extraction Throughput Math

If you have 500,000 Service Records in SysAid, extracting them at 500 items per request requires 1,000 API calls. At the maximum rate of 1,000 requests per 5 minutes, extraction takes a minimum of 5 minutes of pure network time. In practice, response payload size (typical Service Record responses range from 2–8 KB per record) and network latency reduce the effective throughput to roughly 30,000 to 50,000 records per minute. Factor in per-record calls for activities, related items, and attachments, and total extraction time increases significantly.

For a representative mid-size migration (100,000 Service Records, 200,000 activities, 50,000 attachments):
- Service Records: ~200 API calls → ~1 minute
- Activities: ~400 API calls (at 500/page) → ~2 minutes
- Attachments: ~50,000 API calls → ~250 minutes
- **Total extraction time: ~4.5 hours minimum**, dominated by attachment downloads

```python
import requests
import time

def extract_sysaid_records(session, base_url, offset, record_type="incident"):
    url = f"{base_url}/api/v1/sr"
    params = {
        "limit": 500,
        "offset": offset,
        "type": record_type,
        "fields": "id,title,status,priority,urgency,impact,assignedTo,requestUser,ciId,createDate,closeTime,description"
    }
    cookies = {"JSESSIONID": session["jsessionid"]}
    response = requests.get(url, params=params, cookies=cookies)

    remaining = int(response.headers.get("X-RateLimit-Remaining", 100))
    reset_time = int(response.headers.get("X-RateLimit-Reset", 0))

    if response.status_code == 429:
        sleep_seconds = max(reset_time, 300)
        time.sleep(sleep_seconds)
        return extract_sysaid_records(session, base_url, offset, record_type)

    if remaining < 50:
        time.sleep(30)  # Preemptive backoff

    return response.json()
```

Use `fields`, `expand`, `filters`, `sort_by`, and `sort_dir` parameters aggressively so you do not overfetch. SysAid's `expand` support for `requestUser`, `ci`, and `asset` can reduce follow-up lookups. ([developers.sysaid.com](https://developers.sysaid.com/reference/searchservicerecords))

## How to Load Data into ServiceNow: Import Sets, Batching, and Semaphores

ServiceNow provides three primary ingest methods: Import Sets with Transform Maps, the Table API, and the Attachment API. For migrations, Import Sets are the recommended path because they provide staging, transformation, and audit trail capabilities. Use the Table API mostly for lookups and limited post-load updates. ([servicenow.com](https://www.servicenow.com/docs/r/api-reference/rest-apis/c_ImportSetAPI.html))

### Deploying Migration Artifacts with Update Sets

Before loading data, deploy your migration infrastructure — Import Set tables, Transform Maps, custom `u_` fields, and any supporting Business Rules — using ServiceNow Update Sets. Create a dedicated Update Set (e.g., "SysAid Migration Artifacts") in your sub-production instance, build all migration components there, and promote the Update Set to production after testing. This ensures your migration configuration is version-controlled, auditable, and reversible. If scoped applications are used in your organization, consider packaging the migration artifacts as a scoped app for cleaner lifecycle management.

### Import Set API and Batch Sizing

<cite index="16-2">The docs (insertMultiple) suggest using 200 records per operation, and gradually increasing while watching instance performance.</cite> This is the recommended starting point for the `insertMultiple` method on Import Set tables.

The `insertMultiple` endpoint is asynchronous by default, accepts only string name-value pairs, and can sequence dependent jobs with `run_after` in async mode. The Import Set batch size for file-based imports defaults to 1,000 records. <cite index="13-9">If neither property is set, use the default batch size of 1000.</cite> You can configure this via the `glide.import_set_load_batch_size` system property.

### Semaphore-Based Rate Limiting

ServiceNow does not enforce a fixed requests-per-minute limit. Instead, it uses semaphore-based concurrency control.

<cite index="31-3,31-4,31-5,31-6">Semaphores are internal controls that manage how many transactions can run in parallel. When transactions are long-running or complex, they occupy these resources for longer periods, which can slow down or delay new incoming requests. If the system becomes saturated, it starts queuing transactions. Once the queue reaches its limit, additional requests may be rejected with an HTTP 429 Too Many Requests error.</cite>

<cite index="33-6,33-7">The REST API semaphore pool (called "API_INT") allows only 4 concurrent requests per node with a queue depth of 50. When all threads are busy and the queue is full, additional requests are rejected with HTTP 429.</cite>

Your migration scripts must implement exponential backoff and retry logic. Limit concurrent API calls to 2 to 3 threads and monitor for 429 responses. If you push too many concurrent batches, you will degrade the performance of the entire ServiceNow instance for active users.

Loading 500,000 records in batches of 200 means 2,500 API calls. If each batch takes 3 seconds to process through the Import Set transform maps, the total load time is roughly 125 minutes — assuming you do not block the semaphores. Push too many concurrent threads and ServiceNow throttles the connection, multiplying your load time.

### Attachment Loading

<cite index="51-2">The default maximum attachment size is 1024 MB for new base system instances.</cite> The REST API has a practical payload limit of approximately 25 MB per request. Attachments larger than 25 MB require chunked upload or the Attachment API's multipart form data method. ServiceNow uploads one file per request, so attachment loading is inherently sequential per record.

### CMDB Loading

For CMDB data, route CI imports through ServiceNow's IRE and `CMDBTransformUtil` so identification and reconciliation rules are enforced during import. Blind inserts into `cmdb_ci` tables are one of the fastest ways to create duplicates that pollute your CMDB for months. Set up identification rules that match on serial number, name + IP address, or another unique combination from your SysAid CI data before running the first import. ([servicenow.com](https://www.servicenow.com/docs/r/servicenow-platform/configuration-management-database-cmdb/c_CMDBIdentifyandReconcile.html))

For more on ServiceNow's import constraints, see our guide on [10 ServiceNow data migration challenges](https://clonepartner.com/blog/blog/10-servicenow-data-migration-challenges-how-to-overcome-them/).

## Migration Approaches: Native vs. iPaaS vs. Managed Service

There are four viable approaches to migrating SysAid data into ServiceNow. The right choice depends on volume, CMDB complexity, and internal engineering capacity.

**CSV Export and Import Set Upload.** Export data from SysAid as CSV files (via built-in admin console reports or API extraction), then upload to ServiceNow Import Set tables with Transform Maps. Works for small datasets under 10,000 records with no CMDB and no attachment requirements. No API development required, but attachments, relationships, and activity history are lost.

**API-Based Custom ETL.** Build custom scripts that extract from SysAid's REST API, transform in a staging database (PostgreSQL, SQLite, or a dedicated staging schema), and load into ServiceNow via the Import Set API. Full control over transformation logic. Handles attachments, relationships, and activity history. Supports incremental and delta sync. Requires 2 to 4 weeks of engineering time from a developer experienced with both APIs.

**iPaaS (Workato, Zapier, Make).** Use pre-built connectors to map SysAid events to ServiceNow actions. Good for real-time event-driven sync during a coexistence period. Poor choice for one-time bulk migration. Per-task pricing (typically $0.01–$0.05 per task on Workato/Make) makes bulk migration of 100K+ records expensive ($1,000–$5,000+ in task costs alone). Cannot handle complex CMDB relationship rebuilding or multi-table decomposition of Service Records.

**Managed Migration Service.** A migration engineering team builds and runs the full ETL pipeline, including extraction, transformation, loading, relationship rebuilding, and validation. No internal engineering burden. Handles edge cases, retries, and validation. Provides audit trail for compliance.

| Criteria | CSV Import | Custom ETL | iPaaS | Managed Service |
|---|---|---|---|---|
| Best for | < 10K records | 10K to 500K+ records | Ongoing sync | Enterprise, compliance |
| Attachments | No | Yes | Limited | Yes |
| CMDB Relationships | No | Yes (manual) | No | Yes |
| Activity History | No | Yes | Partial | Yes |
| Engineering Effort | 1 to 2 days | 2 to 4 weeks | 3 to 5 days setup | 0 (handled externally) |
| Risk of Data Loss | High | Medium | Medium | Low |

If your environment is small and flat, CSV plus Import Sets can work. If you need historical fidelity, CMDB integrity, and controlled cutover, build or buy a real ETL pipeline.

## Step-by-Step SysAid to ServiceNow Migration Process

The order of operations matters. Loading records in the wrong sequence creates orphaned references and broken relationships. If you load a ticket before the user who requested it, the caller field will be blank — and fixing that retroactively in a production instance is painful.

**Step 1: Audit the source model.**
Pull sample Service Records, users, companies, assets, CIs, notes, activities, attachments, and custom field metadata from SysAid. Document your record counts, custom field inventory (total count, field types, list-type fields requiring metadata translation), and attachment volume (count and total size in GB) before mapping anything.

**Step 2: Freeze the routing rules.**
Decide exactly which SysAid Requests become `sc_request` + `sc_req_item`, and which become incidents or another task type. This is a design decision that must be locked before you build anything. Document the decision with examples: "SysAid Requests with category 'Software License' become sc_req_item under a 'Software Request' catalog item. All other Requests become incidents."

**Step 3: Load reference data.**
Insert Companies, then Departments, then Users into ServiceNow. Store the resulting `sys_id` for every record in a mapping database (a simple table with columns: `sysaid_entity`, `sysaid_id`, `servicenow_table`, `servicenow_sys_id`). Every subsequent load depends on this mapping.

**Step 4: Extract and load CMDB CIs.**
Pull CIs from SysAid (`/api/v1/ci`). Map each SysAid CI type to the correct ServiceNow CI class (`cmdb_ci_server`, `cmdb_ci_computer`, `cmdb_ci_win_server`, `cmdb_ci_linux_server`, etc.). Load CIs using IRE and store the ID mapping. Then load CI relationships into `cmdb_rel_ci`, mapping each SysAid relation type to a ServiceNow `cmdb_rel_type`.

**Step 5: Extract and load Assets.**
Pull assets from SysAid (`/api/v1/assets`). Map to `alm_asset` records in ServiceNow, linking to the correct `cmdb_ci` record using the mapping table from Step 4.

**Step 6: Extract, classify, and transform Service Records.**
Pull all Service Records from SysAid, filtered by type. Route each to the correct ServiceNow staging table:
- `type=incident` → `incident`
- `type=request` → `sc_request` + `sc_req_item` (or `incident`, per your routing decision from Step 2)
- `type=change` → `change_request`
- `type=problem` → `problem`

Transform field values: status codes, priority mappings, picklist values. Replace SysAid user IDs and CI IDs with the ServiceNow `sys_id` values from your mapping tables. Strip or sanitize HTML from description fields. Convert date formats to ServiceNow's expected `YYYY-MM-DD HH:mm:ss` UTC format.

```python
SYSAID_TO_SNOW_STATUS = {
    1: 1,   # New → New
    2: 2,   # In Progress → In Progress
    3: 6,   # Resolved → Resolved
    4: 7,   # Closed → Closed
    # Add your tenant-specific mappings
}

for sr in sysaid_service_records(limit=100):
    target = route_service_record(sr)  # Returns 'incident', 'change_request', etc.
    staged_row = transform(sr, target, id_map=mapping_db, status_map=SYSAID_TO_SNOW_STATUS)
    write_to_import_stage(target, staged_row)

run_import('u_cp_incident_stage')
run_import('u_cp_problem_stage')
run_import('u_cp_change_stage')
run_import('u_cp_request_stage')
```

**Step 7: Load Service Records into ServiceNow.**
Use Import Set tables with Transform Maps. Keep batch sizes at 200 records for API-based loads using `insertMultiple`. Process records in chronological order (oldest first) to preserve temporal integrity and ensure parent records exist before children.

**Step 8: Load Activity History.**
Extract activities and notes from SysAid for each Service Record. Load as `sys_journal_entry` records, preserving the original timestamp and author attribution. The `element_id` references the target record's `sys_id`, and `element` should be set to `work_notes` or `comments` depending on the activity type.

**Step 9: Load Attachments.**
Download each attachment binary from SysAid individually. Upload to ServiceNow's Attachment API, linking to the correct table and `sys_id`. This is the most time-consuming step due to SysAid's per-attachment API call requirement. Implement parallel download (2–3 threads on SysAid side) and sequential upload (1 thread on ServiceNow side to avoid semaphore saturation).

**Step 10: Rebuild cross-record relationships and validate.**
Parent-child links between incidents and problems, linked incidents on change requests, and any custom relationships must be re-established using the ID mapping tables. Load these as `task_rel_task` records. Run record-count reconciliation and field-level spot checks (detailed in the Validation section below).

> [!CAUTION]
> Do not load attachments before the parent ticket mapping is final. Reattaching thousands of files by hand is the kind of cleanup that turns a two-week project into a two-month one.

Retry rules should differ by platform. On SysAid, back off to the `X-RateLimit-Reset` header value when you hit 429. On ServiceNow, honor `Retry-After` for REST rate limits, cut concurrency when API_INT semaphore depth rises, and keep a durable map of source ID to target `sys_id` so replays are idempotent (check-before-insert or use coalesce fields in Transform Maps).

For a broader look at data sequencing, review our [Help Desk Data Migration Playbook](https://clonepartner.com/blog/blog/help-desk-data-migration-playbook/).

## How Long Does a SysAid to ServiceNow Migration Take?

A realistic timeline depends on record volume, CMDB complexity, and the number of custom fields.

| Phase | Duration | Exit Criteria |
|---|---|---|
| Discovery and audit | 3 to 5 days | Record counts, custom fields, attachment volume (count + GB), and request routing rules are documented |
| Field mapping and transform design | 3 to 5 days | Approved mapping document, ServiceNow Import Set tables and Transform Maps created, Update Set promoted to sub-prod |
| Script development and testing | 5 to 10 days | Extraction, transformation, and load scripts built and tested against sub-production instance |
| Trial migration (rehearsal) | 2 to 3 days | Full migration on sandbox, counts reconciled within 0.1%, relationships validated, stakeholder review |
| Production migration | 1 to 3 days | Final migration executed. Larger datasets with attachments take longer |
| Validation and UAT | 2 to 3 days | Stakeholder sign-off, agent testing with migrated data, SLA field verification |
| **Total** | **3 to 6 weeks** | For 50,000 to 200,000 records with CMDB |

Smaller migrations (under 10,000 records, no CMDB) can complete in 1 to 2 weeks. Enterprise migrations with 500,000+ records and deep CMDB hierarchies may extend to 8 to 10 weeks.

### Phased vs. Big-Bang vs. Incremental

- **Big-bang** works when the organization can tolerate a weekend cutover window and the dataset is manageable (under 100,000 records total). All data moves at once; SysAid is decommissioned Monday morning.
- **Phased** is better for organizations that need to migrate by department or process (incidents first, then changes, then CMDB). Reduces risk but extends the coexistence period and requires channel routing during overlap.
- **Incremental** (with ongoing delta sync) is required when both platforms must run in parallel for weeks or months. Requires a delta detection mechanism (comparing SysAid `modifyDate` against last sync timestamp) and idempotent upsert logic on the ServiceNow side. Adds 1–2 weeks of engineering complexity but eliminates downtime.

### Key Risks

| Risk | Likelihood | Mitigation |
|---|---|---|
| Wrong table routing for Requests | High | Freeze request routing rules before build. Test with real fulfillers using 50+ sample records |
| Duplicate CIs from blind inserts | High | Use IRE and identity rules, not direct table inserts. Set identification rules before first CI import |
| API rate limiting (SysAid) | High | Implement token bucket rate limiter. Read `X-RateLimit-*` headers. Budget 250+ minutes for attachment extraction |
| Broken caller or assignee references | Medium | Preload users and maintain immutable external ID mapping. Validate with a query for null `caller_id` post-load |
| Attachment backlog | Medium | Test export and upload speed on day 1. Parallelize SysAid downloads (2–3 threads), serialize ServiceNow uploads |
| Semaphore saturation (ServiceNow) | Medium | Start with 1 thread, monitor 429 responses, cap concurrent threads at 2 to 3. Schedule loads during off-hours |
| Data truncation | Medium | Audit field lengths in ServiceNow before test load. ServiceNow `short_description` is 160 chars; SysAid `title` may be longer |
| Reporting drift after go-live | Medium | Rebuild dashboards against new tables before cutover. Verify key metrics (open incident count, MTTR) match between systems |
| Import Set auto-cleanup | Medium | ServiceNow deletes import sets older than 7 days by default. Export transform logs before they age out |

## Edge Cases and Known Limitations

These are the failure modes that generic guides skip.

**Duplicate users.** SysAid may have duplicate user records (same email, different `id` values). ServiceNow enforces unique `user_name`. Deduplicate before loading — merge duplicate SysAid users in your staging database and map all source IDs to the single canonical ServiceNow `sys_id`. Otherwise your import will fail on unique constraint violations.

**Orphaned attachments.** SysAid attachments linked to deleted Service Records will fail to load because the parent record does not exist in ServiceNow. Decide in advance whether to skip, archive to a separate table, or load to a catch-all record.

**Multi-level CMDB relationships.** SysAid supports CI-to-CI relationships but does not enforce a hierarchy. ServiceNow's CMDB expects relationships to follow the Common Service Data Model. Flat SysAid relationships may need restructuring. Migrating a server and its installed software requires creating records in `cmdb_ci_server`, `cmdb_ci_spkg`, and linking them in `cmdb_rel_ci` with a `cmdb_rel_type` of "Runs on::Runs" or similar. A simple CSV import cannot handle this logic.

**Custom fields exceeding ServiceNow limits.** ServiceNow allows up to 500 custom fields per table (a soft limit; exceeding it degrades form load performance). <cite index="45-1">The CMDB allows you to create as many item types as you like, and you have 250 customizable fields to record any information you need about each of your items.</cite> If your SysAid instance has 250 custom CI fields, they will fit, but plan field types carefully in ServiceNow. Consider whether some SysAid custom fields should become ServiceNow Extended Attributes or entries in a related list rather than direct columns.

**Attachment size via API.** ServiceNow's REST API has a practical payload limit of approximately 25 MB per request. Attachments larger than this require the multipart upload method or chunking. SysAid caps file attachments at 50 MB and blocks certain executable and HTML-like file types (.exe, .bat, .htm). ([documentation.sysaid.com](https://documentation.sysaid.com/docs/view-attachments))

**Webhook limitations for custom fields.** If a SysAid service record was created through the API, custom fields are not included in the creation webhook payload. This matters if you are using webhooks for incremental sync during a coexistence period — you will need a follow-up GET call to retrieve custom field values for webhook-triggered records. ([developers.sysaid.com](https://developers.sysaid.com/docs/custom-fields))

**SLA data.** SysAid SLA counters are calculated values. ServiceNow's SLA engine (`task_sla`) will not retroactively compute SLAs for imported records. Historical SLA outcomes are better stored as migrated custom field values (`u_sysaid_sla_met`, `u_sysaid_sla_elapsed_minutes`, `u_sysaid_sla_breach_time`) or archived reports than replayed through the live SLA engine.

**Import Set cleanup.** ServiceNow has a default cleanup job (`Import Set Deleter`) that removes import sets older than 7 days along with associated staging records. Export your transform logs and error records before they age out if you need a durable audit trail from rehearsal runs. You can extend the retention by modifying the `glide.import_set_cleanup_age` property, but do so intentionally and revert after migration. ([servicenow.com](https://www.servicenow.com/docs/r/yokohama/integrate-applications/system-import-sets/c_ImportSetsKeyConcepts.html))

**SysAid workflow and automation rules.** These cannot be exported via API. They must be manually audited in the SysAid admin console (under Settings → Workflow) and recreated in ServiceNow as Business Rules, Flows, or Scheduled Jobs. Document trigger conditions, filter criteria, and actions for each rule before attempting recreation.

**Data privacy and masking.** For GDPR, HIPAA, or SOX-regulated environments, ensure that PII (names, email addresses, phone numbers in ticket descriptions) is handled appropriately during extraction and staging. If your staging database is not within the same compliance boundary as your production systems, apply field-level masking or encryption during extraction and decrypt only during the ServiceNow load phase. Maintain a data processing agreement with any third-party migration vendor.

## How to Validate a SysAid to ServiceNow Migration

Do not trust API success codes blindly. Validate the data inside the ServiceNow instance using a structured approach.

1. **Record-count reconciliation.** Compare total counts per object type: incidents, requests, changes, problems, users, CIs, assets, attachments. Source counts should match destination counts within 0.1% (accounting for intentional exclusions like orphaned records or deduplicated users). Run this query in ServiceNow: `incident.list?sysparm_query=u_sysaid_idISNOTEMPTY` and compare against your source count.

2. **Field-level spot checks.** Sample 50 to 100 records per object type across different categories — open tickets, closed tickets, high-priority, reassigned, and attachment-heavy cases. Verify that status, priority, assigned_to, created_date, and resolved_date match between source and target. Use a spreadsheet with side-by-side comparison columns.

3. **Null reference audit.** Run queries for records with null values in critical reference fields that should be populated: `incident.list?sysparm_query=caller_idISEMPTY^u_sysaid_idISNOTEMPTY`. Any results indicate broken reference mappings.

4. **Relationship integrity.** Verify that CI-to-incident links, parent-child ticket references, company assignments, and user assignments resolve correctly in ServiceNow. Spot-check 20+ CMDB relationships by navigating the CI record and confirming related items appear.

5. **Attachment verification.** Confirm that attachments are accessible and renderable on their target records. Check file sizes against the source system. Run: `sys_attachment.list?sysparm_query=table_name=incident^ORtable_name=change_request` and compare counts.

6. **Timestamp accuracy.** Verify that created, updated, and resolved timestamps match the source system. Timezone shifts are a common failure mode — SysAid may return timestamps in the account's local timezone despite documenting UTC, so compare a sample of 10+ records with known timestamps.

7. **UAT with real agents.** Have 3 to 5 IT agents work in ServiceNow using migrated data for 1 to 2 days before go-live. Ask them to search for old SysAid IDs (using the `u_sysaid_id` field), open records, verify activity history, and confirm attachments are accessible. Agents find issues — missing categories, wrong assignment groups, truncated descriptions — that automated checks miss.

### Rollback Plan

Your rollback plan should include these concrete elements:
- **Keep SysAid readable** in read-only mode for at least 30 days post-cutover
- **Preserve the ID crosswalk** mapping database indefinitely — it is your Rosetta Stone for any post-migration corrections
- **Do not destroy source data** until validation is complete and stakeholders have signed off
- **Script a ServiceNow cleanup** that can delete all records with `u_sysaid_id IS NOT EMPTY` from each target table, effectively reverting the import
- **Switch inbound channels** (email routing, portal URLs, agent bookmarks) only after validation passes
- **Document the rollback trigger criteria**: e.g., "If record count variance exceeds 1% or more than 5% of spot-checked records have incorrect field values, execute rollback"

For a complete post-migration validation framework, see our [help desk migration QA checklist](https://clonepartner.com/blog/blog/help-desk-data-migration-qa-checklist/).

## Build In-House or Use a Managed Migration Service?

**Build in-house when:**

- Your dataset is under 10,000 records with no CMDB
- You have a ServiceNow developer with Import Set and Transform Map experience on staff
- You can tolerate a multi-day cutover window
- Compliance and audit requirements are minimal
- Your SysAid Requests map cleanly to either incidents or a well-defined catalog model

**Use a managed service when:**

- Your dataset exceeds 50,000 records or includes CMDB data
- You need zero-downtime migration with delta sync
- Compliance requirements (SOX, HIPAA, GDPR) mandate a documented audit trail and chain of custody
- Your SysAid Requests do not map cleanly to Service Catalog and require case-by-case routing logic
- Your engineering team cannot absorb 2 to 4 weeks of migration work alongside existing priorities
- You have significant attachment volume (50,000+ files) that requires optimized extraction scheduling

The hidden cost of in-house migration is not the initial build — it is the re-work. Broken relationships, missed attachments, and incorrect field mappings typically surface 1 to 2 weeks after go-live, requiring a second or third corrective pass. This re-work compounds quickly when agents are already using ServiceNow in production and new records are being created alongside corrective imports. The internal engineering cost of a DIY migration (2 to 4 weeks of a senior developer's time at $80–$120/hour fully loaded = $25,000–$75,000 in labor) often approaches or exceeds the cost of a managed service.

ClonePartner handles the complex ETL logic required to split SysAid's unified Service Records into ServiceNow's distinct tables automatically. We manage SysAid's 1,000-request-per-5-minute rate limit and ServiceNow's semaphore queues with built-in retry logic and record-level audit trails. We preserve exact `sys_id` mappings and CMDB relationships that generic iPaaS tools and CSV exports break.

For a broader perspective on the build-vs-buy decision, see our [in-house vs. outsourced migration analysis](https://clonepartner.com/blog/blog/in-house-vs-outsourced-data-migration/).

> Planning a SysAid to ServiceNow migration? Our team has handled ITSM migrations with complex CMDB relationships, high-volume attachments, and strict compliance requirements. Book a free 30-minute technical consultation to discuss your dataset and timeline.
>
> [Talk to us](https://cal.com/clonepartner/meet?duration=30)

## Frequently asked questions

### How long does a SysAid to ServiceNow migration take?

A typical mid-size enterprise migration (50,000 to 200,000 records) takes 3 to 6 weeks from discovery to go-live. Smaller migrations with under 10,000 records and no CMDB can complete in 1 to 2 weeks. Enterprise migrations with 500,000+ records and deep CMDB hierarchies may extend to 8 to 10 weeks. The largest variable is attachment volume, because each SysAid attachment requires an individual API call to download.

### What data cannot be migrated from SysAid to ServiceNow?

SysAid workflow automations, routing rules, notification templates, and dashboard configurations cannot be exported via API and must be rebuilt in ServiceNow. SLA elapsed-time counters are calculated values that ServiceNow's SLA engine will not retroactively compute for imported records. Contextual attachment placement inside rich text fields also does not transfer 1-to-1.

### Can SysAid CMDB data be preserved in ServiceNow?

Yes, but not as a 1-to-1 copy. SysAid CI types must be mapped to ServiceNow's class-based CMDB hierarchy. CI relationships must be individually mapped from SysAid's relation types to ServiceNow's cmdb_rel_type records. Use ServiceNow's IRE (Identification and Reconciliation Engine) during import to avoid creating duplicate CIs.

### Can SysAid ticket history be preserved in ServiceNow?

Yes. SysAid activity history (notes, status changes, assignment changes) can be migrated as sys_journal_entry records in ServiceNow. Each journal entry preserves the original author and timestamp. Native ServiceNow audit and history behavior is not a 1-to-1 copy target, but human-readable history is fully preservable for compliance and operational purposes.

### Is there downtime during a SysAid to ServiceNow migration?

A big-bang migration requires a freeze window of 4 to 24 hours where no new tickets should be created in SysAid. An incremental migration with delta sync can reduce this to under 1 hour. The bulk of historical data is migrated while SysAid is still active, and only the delta (new and modified records since the bulk load) is migrated during the cutover window.
