Home / Question Hub / Automation & Flows
Automation & Flows
Flow Designer, classic Workflow, Transform Maps and Integrations — how work and data actually move on the platform.
No questions match your search.
Flow Designer
16 questionsFlow Designer for all new automation: it's the strategic engine — low-code, IntegrationHub-native, scoped-app friendly, better runtime diagnostics. Classic Workflow remains for maintaining legacy processes and a few gaps (some deep SC order guide behaviors). Answer as: "new = Flow, existing workflow = maintain until migrated."
- Natural-language, low-code design — process owners can read it.
- Reusable actions and subflows with typed inputs/outputs.
- IntegrationHub spokes plug in directly.
- Execution details per run — far better debugging than workflow contexts.
- Runs asynchronously by default, easing form-save performance.
Record (created / updated / created-or-updated, with conditions), Schedule (daily/weekly/repeat), Application triggers (inbound email, SLA task, service catalog), and flows with no trigger called from other flows/subflows/script. MetricBase/other plugins add more.
Use the Do in Parallel flow logic block — branches run concurrently and the flow proceeds when all complete. Typical for creating several tasks at once or calling multiple systems simultaneously.
Via data pills: every trigger and action exposes typed outputs that later steps drag in as inputs. For values you compute mid-flow, use Set Flow Variables and reference those pills downstream.
Not directly — client code can't invoke FlowAPI. Bridge through the server: GlideAjax to a Script Include that calls sn_fd.FlowAPI.getRunner().subflow('scope.name').inBackground().withInputs(inputs).run(). Or avoid the bridge entirely: let the flow trigger on the record change the client is about to make.
With IntegrationHub: drop a spoke action (Jira, Teams, REST step…) into the flow, backed by a Connection & Credential alias. Without IH licensing, a custom action containing a script step using RESTMessageV2 does the same job less elegantly.
In Execution Details a context moves through Waiting/Queued → In Progress → Complete, or lands in Error / Cancelled; flows with Wait steps sit in Waiting until the condition or timer releases them. Knowing where to see this (Flow Designer → Executions) is half the answer.
Inline script steps inside custom actions (inputs in, outputs out — keep them pure), the "Script" option on action input fields for computed values, and FlowAPI for calling flows from scripts. Discipline: logic belongs in Script Includes the script step calls, so flows stay readable.
A flow has a trigger and runs on its own when the trigger fires. A subflow has no trigger — it's a callable unit with declared inputs and outputs, invoked by flows, other subflows or script. Same relationship as program vs function.
OOB core actions (Create/Update/Look Up Record, Send Email, Ask for Approval, Wait), spoke actions from IntegrationHub, and custom actions you build from steps (script, REST, PowerShell, payload builder…). Have one custom action story ready: inputs → steps → outputs, and why an OOB action didn't suffice.
Classic workflow runs synchronously in the triggering transaction by default (the user's save waits for activities until a wait state), while flows default to running asynchronously in the background (with a "run in foreground" option when the transaction must see results). That sync/async default plus tooling (spokes, execution details, scoped support) is the "exact difference" answer.
In the subflow editor, open the Inputs & Outputs section: define each with a label, name and type (string, reference with table, boolean…). Inputs arrive as pills for the caller to fill; outputs are assigned inside the subflow with "Assign Subflow Outputs" and surface as pills in the caller after the call.
The licensed extension of Flow Designer for integrations: prebuilt spokes (Jira, Slack, Teams, Azure AD…), protocol steps (REST, SOAP, PowerShell, SSH) for custom actions, and Connection & Credential aliases so environments swap cleanly. A good "yes" story: an onboarding flow calling the Azure AD spoke to create accounts, with the REST step fallback for one API the spoke didn't cover.
Reusable, parameterized process logic — the function of the flow world. Need it for: reuse across flows (one "assign and notify" used by ten processes), tidy decomposition of big flows, and unit-testable automation (run the subflow alone with test inputs).
Flow triggered on sys_user record created (with conditions), then a Create Record action on sys_user_has_role setting user = trigger record and role = looked-up role. Mention the governance caveat: auto-granting roles should be tightly conditioned and audited.
Workflow (Classic)
13 questionsThe classic graphical automation engine: a canvas of activities (approvals, tasks, conditions, timers, scripts) connected by transitions, attached to a table and started when its condition matches — most famously driving service catalog request fulfillment. Superseded for new work by Flow Designer, still everywhere in existing instances.
- Approval - User/Group — gate on human sign-off.
- Create Task / Catalog Task — spawn fulfillment work.
- If / Switch — branch on record data.
- Timer — wait a duration or until a date.
- Run Script — server script inside the context (keep it thin!).
- Wait for condition — pause until the record reaches a state.
The Turnstile activity allows a transition through it only a set number of times; further attempts exit through its overflow path. Place it inside any loop-back (e.g. rework cycles) so a badly-behaved condition can't spin forever — the workflow-native circuit breaker.
Through the workflow scratchpad: workflow.scratchpad.myValue = '...' in one activity, read it in a later one. Scratchpad values persist in the context across activities (and survive timers) as long as they're simple strings/numbers.
Define workflow inputs on the subworkflow; the parent's Workflow activity then shows those inputs as fields to map from its own data/scratchpad. Inside the child they're available as workflow.inputs.u_name.
Set workflow.scratchpad values in the child? No — the clean mechanism is return values: the child sets workflow.returnValue (or output variables), and the parent reads it from the Workflow activity's result. The pragmatic alternative many teams use: write to a field on the driven record both contexts can see.
It rewinds execution to a previously completed activity and re-runs from there — canonical use: an approval is rejected, roll back to the "revise request" step so the requester fixes and resubmits, repeating approvals without duplicating canvas.
They expect one end-to-end story with: multi-level dynamic approvals (approvers computed at runtime), parallel task branches with a join, timers with escalation, subworkflow reuse, scratchpad data handoffs, and how you debugged contexts when it stalled. Prepare that one story properly rather than five shallow ones.
- Flows are async by default; workflows run in-transaction.
- Flows have typed inputs/outputs and reusable actions; workflows have scratchpad and activities.
- IntegrationHub spokes only exist in Flow Designer.
- Flows give per-run execution details; workflow debugging means reading contexts.
- Workflow is legacy-maintenance only; all new automation goes to Flow Designer.
// In a workflow Run Script on sc_req_item
var vars = current.variables;
for (var name in vars) {
workflow.scratchpad[name] = String(vars[name]);
}
On the task side, variables show via the variable editor when the catalog task is created with "map variables" (slushbucket on the Catalog Task activity). Script access is current.variables.variable_name.
Modern answer: approval policies on the change model — decision tables of conditions → approval definitions (who approves in which state). Legacy answer: approval activities/rules in the change workflow. Name both and say which your project used and why.
The Approval activity supports a scripted approval condition: count approvals vs total via the counts object and return approved when counts.approved / counts.total > 0.5. In Flow Designer, "Ask for Approval" has rule options (anyone / everyone / percentage-style custom rules) that express the same without script.
Same intent, different generations: workflow = classic canvas, synchronous, global-scope era; flow = modern engine, asynchronous, low-code, integration-native, scoped-app ready. If asked in one line: "Workflow is the past I maintain; Flow Designer is where I build."
Transform Maps
13 questionsThe transform script events: onStart (before any row), onBefore (before each row writes), onAfter (after each row writes), onComplete (after all rows), plus onChoiceCreate, onForeignInsert and onReject for special cases — and field-level source scripts on individual field maps.
onStart → per row: field maps (with their source scripts) → onBefore → target write → onAfter → next row … → onComplete. onChoiceCreate/onForeignInsert fire within a row when a missing choice or referenced record is encountered.
The matching key: field(s) marked coalesce decide whether an incoming row updates an existing target record (match found) or inserts a new one (no match). No coalesce at all = every run inserts duplicates — the most common import mistake in existence.
Yes — mark several field maps coalesce and they act as a composite key (all must match, AND). Conditional and scripted coalesce exist for hairier matching. Multi-coalesce example: employee imports keyed on company + employee_number.
In an onBefore script, skip rows that didn't match: if (action === 'insert') { ignore = true; }. The action variable says what's about to happen; setting ignore = true skips the row. (The reverse — insert-only — is action === 'update'.)
source (the staging row), target (the target GlideRecord), map (the transform map), action ('insert'/'update'), ignore (set true to skip the row), error/error_message (fail the row with a reason), log (import log helper), and in onComplete aggregate context.
When a mapped reference field's value doesn't exist on the referenced table, the import can create that referenced ("foreign") record on the fly — the onForeignInsert script fires to control what gets created. Powerful and dangerous: unreviewed feeds happily invent users and companies unless you validate.
Options: split at the source (multiple files / paginated data source pulls), use a scheduled data source importing incrementally (delta by updated-since), or the Import Set API posting batches. Also set the import set table to clean up processed rows and watch the "maximum row" property limits. The principle: never one monolithic multi-hundred-thousand-row synchronous import.
// onBefore
if (source.getValue('u_name') === '' && source.getValue('u_email') === '') {
ignore = true;
}
Guard the key columns in onBefore and set ignore = true — trailing blank spreadsheet rows are the classic culprit.
No hard product maximum, but practical governors: file upload size limits, the glide.db.max_view_records-style import properties, transaction quotas, and memory. Big loads should go scheduled/chunked; quote "there's no magic number, but past tens of thousands of rows per set you design for chunking" and you sound like you've done it.
For choice/reference targets, the field map's Choice action decides what to do with unknown incoming values: create (add the new choice/record), ignore (leave the field, keep the row), or reject (skip the entire row). Default create is how imports quietly pollute choice lists — set it consciously.
Yes, by default the target writes fire business rules, workflows and notifications like any other write. The transform map has a Run business rules checkbox — untick it (documented!) for bulk migrations where you don't want the engine storm; then remember defaults/calculations BRs would have done won't happen.
Practical routes: preprocess the file (cleanest), or import all 100 to the staging table and skip the first 50 in an onBefore script using a row counter in an onStart-initialized variable, or filter by a column value that distinguishes them. There's no OOB "start at row N" for data rows — the counter trick is the expected scripting answer.
Integration
27 questionsConnecting the instance with external systems to exchange data or trigger actions — monitoring tools raising incidents, HR systems feeding users, ServiceNow calling out to provision accounts. Split every integration conversation into direction (inbound/outbound), protocol (REST/SOAP/…), authentication, and error handling.
External system → ServiceNow: they call our APIs. Template story: a monitoring tool POSTs alerts to a Scripted REST API; the script validates the payload, deduplicates via correlation_id, creates/updates incidents, and returns the incident number; auth via OAuth with a dedicated integration user holding a minimal role. Mention input validation and GlideRecordSecure — the style guide's REST security rules are interview gold here.
ServiceNow → external system: we call their APIs, via RESTMessageV2/SOAPMessageV2, IntegrationHub spokes, or through a MID Server when the target sits on-prem. Typical: pushing a resolved-incident status back to the customer's ticketing system.
A Java service installed on a machine inside the customer network that acts as the instance's agent behind the firewall — executing Discovery probes, integration calls to on-prem systems, and orchestration steps, communicating with the instance exclusively over outbound HTTPS via the ECC queue.
The cloud instance can't reach private networks — no inbound path through the firewall. The MID Server inverts the connection: it polls the instance for work and performs it locally. Needed whenever the other end of an integration or Discovery target isn't internet-reachable.
GET (read), POST (create / act), PUT (replace), PATCH (partial update), DELETE, plus HEAD/OPTIONS. Know which the Table API uses for what: GET query, POST create, PUT/PATCH update, DELETE delete.
POST creates a new resource (not idempotent — repeat it, get duplicates). PUT replaces a resource wholesale at a known URL (idempotent — repeatable safely). PATCH modifies only the fields sent. Interviewers love the idempotency angle; say the word.
A token-based authorization framework: instead of sending credentials on every call, the client obtains an access token (via authorization code, client credentials, etc.) and presents it as a Bearer header; tokens expire and refresh. In ServiceNow you configure OAuth application registries for both directions — instance as provider (inbound) and as client (outbound).
Table API: generic REST CRUD on any table (/api/now/table/incident) — powerful, direct, ACL-governed. Import Set API: POST into a staging table (/api/now/import/...) so data flows through a transform map — validation, coalesce and mapping applied. For inbound data feeds, prefer Import Set API; raw Table API writes skip your transform safety net.
The built-in console (System Web Services → REST API Explorer) for trying the instance's REST APIs: pick API/version/method, set params, execute live and get generated code samples (including the exact URL and headers). The fastest way to hand a partner team a working example.
var rm = new sn_ws.RESTMessageV2();
rm.setEndpoint('https://api.example.com/tickets');
rm.setHttpMethod('POST');
rm.setRequestHeader('Content-Type', 'application/json');
rm.setRequestBody(JSON.stringify(payload));
var response = rm.execute();
gs.info('[Integration] status: ' + response.getStatusCode());
Or define a REST Message record (endpoint, auth, HTTP methods) and reference it: new sn_ws.RESTMessageV2('My REST Message', 'create_ticket') — preferred, since credentials and endpoints stay configurable.
A custom inbound API you define: base path, resources, HTTP methods, and a script per resource that reads request (pathParams, queryParams, body) and writes response. Use it when Table/Import Set APIs don't fit — custom payload shapes, orchestration of several records per call, or webhooks. Validate every input; see the style guide's Security section for the regex-the-sys_id rule.
SOAP: XML envelope protocol, WSDL contracts, WS-Security, rigid and verbose — still common with legacy enterprise targets. REST: architectural style over plain HTTP verbs, usually JSON, lighter and the default for modern APIs. ServiceNow speaks both (RESTMessageV2 / SOAPMessageV2 outbound; REST APIs and SOAP endpoints inbound).
Patterns to name: retry with exponential backoff on transient failures (429/5xx), an outbound queue table holding failed payloads for a scheduled retry job, IntegrationHub's built-in retry policies on actions, idempotency keys so retries don't duplicate, and a dead-letter status with alerting after N attempts. Never blind-retry 4xx errors — they won't get better.
Walk the framework: requirements (which records, which direction, field mapping, frequency) → auth setup both sides (OAuth/API tokens) → outbound via spoke or RESTMessageV2 on record triggers, inbound via their webhooks hitting a Scripted REST API → correlation IDs stored both sides to prevent loops → error handling, retry, and monitoring dashboards → volume test. Naming loop-prevention via correlation fields is the differentiator.
Internal Server Error — the server failed processing a syntactically fine request (unhandled exception in the endpoint's code, downstream failure). Contrast with 4xx = the caller's fault (400 bad payload, 401 unauthenticated, 403 forbidden, 404 not found). Debug a 500 on your Scripted REST API in the syslog stack trace.
Basic auth (username/password — dev and last resort), OAuth 2.0 (the standard), mutual TLS certificates, and API keys / inbound auth profiles on newer releases. For outbound: the same options against the target, stored in Connection & Credential records or the REST Message auth config.
- Create the OAuth registry entry (provider or client) — client ID/secret.
- Configure grant type (client credentials for system-to-system; auth code for user-context).
- Exchange for tokens; verify expiry/refresh behavior.
- Bind to the REST Message / Connection & Credential alias.
- Test, then lock down scopes and rotate secrets per policy.
Prereqs: an IdP (Azure AD/Okta…), its metadata/certificate, matching user identifiers on both sides (email/employee id), and user provisioning agreed (LDAP/SCIM or JIT). Procedure: install/enable Multi-Provider SSO → create the IdP record from metadata → map the NameID to the user field → test with a test IdP user before enabling per-user/instance-wide → keep a local admin bypass (side door) for IdP outages.
Inbound: a dedicated integration account with the minimal roles granting ACL access to the target tables — plus web_service_admin-adjacent roles only for administering, not for calling; snc_platform_rest_api_access on newer instances. Outbound: no special ServiceNow role (the instance is the client) — the target's credentials matter. The principle to state: least privilege, one account per integration, never a shared human account.
Mutual TLS: both sides present certificates — the server proves itself as usual and the client authenticates with its own cert instead of (or with) credentials. Setup: import the client certificate (sys_certificate) → create a protocol profile binding it to https → attach to the outbound REST/SOAP message; inbound, enable client-cert validation and map certs to users.
200 OK — request succeeded, response has the result (typical for GET/PUT/PATCH). 201 Created — a new resource was created (correct response to a successful POST, with the new record in the body and ideally a Location header). The Table API does exactly this: 200 on updates, 201 on creates.
Outbound: check response.getStatusCode() and haveError(), log with context, classify retryable vs permanent, and never swallow the failure (style guide §7). Inbound (Scripted REST): validate early, return proper status codes with a structured error body via response.setStatus() / setBody(), and wrap processing in try/catch that logs the stack and returns 500 without leaking internals.
Keep environment-varying values out of code: REST Message variables (${variable} substitution filled at runtime with setStringParameterNoEscape()), system properties for endpoints per environment, and Connection & Credential aliases so dev/test/prod swap without touching the flow or script.
Bidirectional ticket synchronization between two service management systems — your incident mirrors the vendor's incident, states and comments flow both ways. Implementation pillars: correlation_id/correlation_display for record pairing, direction-aware update suppression to prevent infinite loops, and mapped state models.
It exposes raw tables: callers need table/field knowledge, writes bypass your transform validation (unlike Import Set API), coarse-grained ACL dependence, chatty for multi-record operations (N calls), version-coupling to your schema (partners break when you rename fields), and easy to misuse for bulk export. For contract-shaped, validated interfaces, use Import Set API or a Scripted REST API façade.
Same recipe regardless of vendor: check for an existing IH spoke first (use it — auth, pagination and errors solved); if none, build a custom spoke: Connection & Credential alias, REST steps per operation, actions with typed inputs/outputs, then compose them in flows. Custom RESTMessageV2 scripts are the no-IH fallback. Structure of the answer beats vendor trivia.