> ## Documentation Index
> Fetch the complete documentation index at: https://www.integrate.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# ETL: ServiceNow Destination

> How to configure the ServiceNow component to write data in your Integrate.io ETL pipeline.

The ServiceNow destination writes each input record to your ServiceNow instance, either into an **import set table** (where your instance's transform maps load the records into their target table) or straight into a **table** through ServiceNow's Table API. It uses your existing ServiceNow connection, and can write a CSV of the result for every record.

Import sets are ServiceNow's recommended path for integrations: your ServiceNow administrator controls how each record is matched and loaded through the import set's transform map.

## Setup

<Steps>
  <Step>Add the **ServiceNow** destination to your package and connect it to the last component of your dataflow.</Step>
  <Step>Select your ServiceNow connection (see [Connection](#connection)).</Step>
  <Step>Choose **Write to**: **Import set table** or **Table**, and pick the table from the list.</Step>
  <Step>For import sets, keep **Records per request** at 1 unless you need to batch (see [Records per request](#records-per-request)).</Step>
  <Step>Map your input fields to ServiceNow columns (see [Schema mapping](#schema-mapping)).</Step>
  <Step>Optionally turn on **Output failed records** and **Output successful records**, then save and run a small test.</Step>
</Steps>

## Connection

Select an existing ServiceNow connection or create a new one. The destination uses the same connection as the ServiceNow source: your **Instance URL** (for example `https://integrateio.service-now.com`), a **username** and a **password**. No other credentials are needed.

The connection's ServiceNow user needs these permissions:

| Writing to | The user needs |
| :- | :- |
| Import set table | Permission to insert into the import set table (typically the `import_set_loader` role). To get each record's transform result when sending several records per request, also **read access** to that import set table (see [Records per request](#records-per-request)). |
| Table | Permission to create records in that table. |

The requests are throttled and retried using the connection's rate limit and retry settings unless you set **Requests per second** on the component.

## Destination properties

| Field | Description |
| :- | :- |
| Write to | **Import set table** (recommended) inserts records into a staging table, and the transform maps defined on it load them into the target table. **Table** inserts each record directly as a new row through the Table API. |
| Import set table / Table | Pick the table from the list your instance returns: its import set tables for **Import set table**, or every table for **Table**. Each entry shows the table's label and name, for example `NetSuite Cost Line Import (u_netsuite_cost_line_import)`. Type part of a name or label to search your instance; more tables load as you scroll. Click **Refresh** to reload the list after a table is added. If the connection's user cannot read your instance's table list, the editor says so and you type the table name instead (the name, not the label). |

### Records per request

**Records per request** applies to import set tables only (1 to 200, default 1).

* **1** sends one request per record. ServiceNow runs the transform immediately and returns each record's result: the import status, the target table and the `sys_id` of the record it created or updated.
* **2 to 200** sends the records together through ServiceNow's `insertMultiple` endpoint, which is faster for large volumes. ServiceNow does not return per-record results for these requests, so Integrate.io reads each row's result back from the import set table once the transform has finished.

<Warning>
  Sending more than 1 record per request needs two things set up on your instance:

  * **A REST Insert Multiple entry** (table `sys_rest_insert_multiple`) for the import set table, with **Column mapping** set to **Column name**. Without it, ServiceNow matches the fields of these requests to column labels, so the column names Integrate.io sends are not stored. When the results can be read back, such records fail with "ServiceNow stored no value for" followed by the columns.
  * **Read access to the import set table** for the connection's ServiceNow user. Without it, records are reported as `accepted` in the successful records output, and rows that the transform map rejects are **not** counted as errors.

  If either is not possible, keep **Records per request** at 1.
</Warning>

Writing to a **Table** always sends one request per record; the Table API has no bulk insert. Records are inserted only: existing records are not updated.

### Advanced options

| Field | Description |
| :- | :- |
| Requests per second | How often a request is sent. Leave empty to use the connection's rate limit. Greater than 0, at most 100. With import sets and more than 1 record per request, this limits requests, not records. |
| Maximum errors | Failed records tolerated before the job fails. Default `0` fails the job on the first failed record. Use `-1` for unlimited. |
| Output failed records (CSV) | Writes a CSV of the records ServiceNow rejected, with the reason for each. |
| Output successful records (CSV) | Writes a CSV of the records ServiceNow took, with the import status and the record it created or updated. |

## Schema mapping

Map each input field to a ServiceNow column, picked from the selected table's columns, including the ones it inherits (for example, the `task` columns on `incident`). **Auto-fill** maps input fields to the columns named after them. The editor warns when a column ServiceNow marks as mandatory is not mapped. If the columns cannot be loaded, for example when the connection's user cannot read the table definitions, you type the column names instead.

* Use column **names** (for example `u_amount`), not labels (`Amount`). With more than 1 record per request, this needs the REST Insert Multiple entry described in [Records per request](#records-per-request).
* Map each column only once.
* Empty (null) input values are not sent, so ServiceNow applies the column's default.
* Date-time fields are sent as `yyyy-MM-dd HH:mm:ss` in UTC, the format ServiceNow expects.

## Result outputs

Both outputs are optional and can go to Amazon S3, Google Cloud Storage, Azure Blob Storage, SFTP or FTPS. A file is only written when it has rows.

**Successful records** has these columns, followed by your mapped fields:

| Column | Description |
| :- | :- |
| Status | The import status: `inserted`, `updated`, `ignored` or `skipped` (as decided by the transform map), or `accepted` when ServiceNow took the record but its transform result could not be read back. For a Table write, always `inserted`. |
| Target Table | The table the record was loaded into. |
| Target sys\_id | The `sys_id` of the record created or updated. |
| Message | Any message ServiceNow returned for the record. |
| Record JSON | The record exactly as it was sent. |

**Failed records** has `Error`, `Record JSON` and your mapped fields.

## Errors and retries

| Situation | What happens |
| :- | :- |
| ServiceNow rate limit (HTTP 429) | The request is retried after the time ServiceNow asks for, up to the connection's retry limit. |
| The instance could not be reached | The request is retried, because it was never sent. |
| Server error or timeout after the request was sent | The records are reported as failed and **not** retried, because inserts are not idempotent and a retry could create duplicates. The error message notes that the records may have been written. Check ServiceNow before re-running them. |
| HTTP 401 | The job fails. Check the username and password on the connection. |
| HTTP 403 | The record fails, usually because of an access rule or a business rule that aborted the insert. The ServiceNow message is in the failed records output. |
| Transform map error | The record fails with the transform's message. |
| A sent value was not stored (more than 1 record per request) | The record fails with "ServiceNow stored no value for" followed by the columns. Add the REST Insert Multiple entry for the import set table, or set **Records per request** to 1. |

The job is not retried automatically for the same reason: a retried attempt would insert again every record the first attempt already wrote, unless your transform map coalesces on a key.

## Best Practices

* Prefer **import set tables** with a transform map that **coalesces** on an external ID. Re-running a job then updates the existing records instead of creating duplicates.
* Keep **Records per request** at 1 unless you send large volumes. Before batching, add the REST Insert Multiple entry for the import set table and give the integration user read access to it.
* Enable **Output failed records** so rejected records can be fixed and re-sent.
* Test with a small sample first, especially when writing directly to a table.

## FAQ

**Q: Can this destination update existing records?**

Not directly. Writing to a **Table** only inserts. To update records, write to an **import set table** whose transform map coalesces on a key field: ServiceNow then updates the matching record and reports the status `updated`.

**Q: Why do my records show the status `accepted`?**

ServiceNow took the record, but its transform result could not be read back. This happens when:

* you send 1 record per request and ServiceNow returns no transform result, because the import set table has no transform map or imports asynchronously;
* you send more than 1 record per request and the result could not be read: the connection's ServiceNow user cannot read the import set table, reading the result failed (an error response or a network error), or the transform had not finished within 10 minutes.

To get a definite status for every record, make sure the import set table has a transform map that runs synchronously. When sending more than 1 record per request, also give the user read access to the import set table; if the transform keeps taking longer than 10 minutes, set **Records per request** to 1.

**Q: Why do batched records fail with "ServiceNow stored no value for ..."?**

With more than 1 record per request, ServiceNow matches fields to column labels unless the import set table has a REST Insert Multiple entry with **Column mapping** set to **Column name**. Ask your ServiceNow administrator to add that entry, or set **Records per request** to 1.

**Q: Can I read data from ServiceNow too?**

Yes, with the ServiceNow source on the same connection. It reads tables such as `incident`, `sys_user`, `cmdb_ci` and `pm_project` (project records).

## Related

<CardGroup cols={2}>
  <Card title="REST API Destination" icon="arrow-right" href="/docs/etl/using-components-rest-api-destination" horizontal />

  <Card title="Salesforce REST API Destination" icon="arrow-right" href="/docs/etl/using-components-salesforce-rest-destination" horizontal />

  <Card title="NetSuite SOAP Destination" icon="arrow-right" href="/docs/etl/using-components-netsuite-soap-destination" horizontal />

  <Card title="Destinations Overview" icon="arrow-right" href="/docs/etl/category/destinations" horizontal />
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.