If your NetSuite integration is failing or creating duplicates, the usual culprits are missing/incorrect externalId usage, “two one‑way” syncs without conflict rules, lack of idempotency keys, or mappings that re‑create records instead of upserting. Stabilize by freezing writes, define a source of truth, dedupe, then enforce upsert + idempotency going forward.
Common symptoms
- Customers, contacts, or items appear 2–5× across subsidiaries.
- Sales Orders/Invoices are re‑created on retries/timeouts.
- Sync “succeeds” but downstream systems show mismatched totals.
- Sandbox works; production throws SuiteScript governance/timeout errors.
- Webhooks/pollers process the same event multiple times.
Why duplicates and failures happen
1) Missing externalId discipline
- Creating by name/email without externalId causes new records instead of updates.
- Relying on internalId from NetSuite breaks cross‑system matching.
2) Two one‑way syncs ≠ bi‑directional
- Independent A→NS and NS→A jobs race each other.
- No conflict resolution (last‑write‑wins vs. merge) defined.
3) No idempotency or upsert semantics
- Retries on 429/5xx re‑post the same payload → duplicate records.
- Missing PUT/PATCH + upsert key (externalId) logic.
4) Concurrency & SuiteScript side effects
- Workflows/User Events create mirror writes (e.g., afterSubmit creates a duplicate).
- Scheduled scripts overlap; governance limits force partial runs.
5) API/transport issues
- SuiteTalk/REST Records timeouts without safe retry patterns.
- Bulk jobs exceed limits; pagination or searchAfter not implemented.
6) Sandbox ≠ Production
- Different custom fields, mandatory flags, numbering, duplicate rules.
- Token‑based auth roles/permissions differ.
7) Model mismatches
- Multi‑subsidiary, multi‑currency, line‑level taxes/discounts not mapped.
- Parent/child relationships (customers, addresses, items) created in wrong order.
Step‑by‑step fix (battle‑tested)
- Freeze non‑essential writes to the noisy objects (e.g., Customer, SO) for 1–2 hours.
- Choose the system of record per object (e.g., Customers in CRM, Finance in NetSuite).
- Export candidates for duplicates (Saved Search by email/name + date range).
- Deduplicate with a clear rule (email+subsidiary, externalId, or hash of legal name+VAT).
- Backfill externalId everywhere (persist the upstream key in NetSuite and the partner system).
- Switch to upsert: use REST Records with
externalId
or SuiteTalk addOrUpdate. - Add idempotency keys: a UUID/header or SHA‑256 of the normalized payload.
- Sequence associations: create parents first (Customer → Address → Contact → SO).
- Harden retries: exponential backoff, jitter, retry‑budget, no blind re‑posts.
- Enable guardrails: duplicate detection rules, unique indexes, validation scripts.
- Observability: structured logs with requestId, externalId, and diff previews.
- Pilot in sandbox, replay a 7‑day event sample, then promote to prod in waves.
NetSuite settings to confirm (checklist)
- Duplicate Detection: Customers/Leads/Contacts (match by Email/Phone/Company).
- Auto‑Numbering: ensure predictable document numbers across environments.
- External ID: visible and writable on target records; enforce uniqueness.
- CSV/REST/SuiteTalk roles: correct permissions; token‑based auth configured.
- Workflows/User Events: scan for afterSubmit “create” actions that re‑insert.
- Subsidiary/Tax Nexus: required fields present in inbound payloads.
- Saved Searches: exclude inactive/merged duplicates from integrations.
- Governance limits: batch sizes fit 10k/usage constraints; add checkpoints.
Prevention architecture (what “good” looks like)
ExternalId‑first matching
Use upstream IDs (CRM/customerId, OMS/orderId) as externalId in NetSuite and as the upsert key in every write path.
True bi‑directional sync
One engine owns both directions with built‑in field‑level change detection, ordered processing, and conflict rules.
Idempotent pipelines
Every request carries a dedupe key; the target rejects replays and treats retries as no‑ops.
Correct sequencing & relationships
Create parents, then children; defer associations until both ends exist (Customer → Address → Contact → Transaction lines).
Change Data Capture (CDC) over poll‑and‑pray
Subscribe to events; avoid high‑frequency polling that multiplies race conditions.
Intermediate data hub
Normalize schemas in a relational DB (Postgres) and let integrations read/write via SQL with strict constraints.
Data quality guardrails
Pre‑flight validators (required fields, enum mapping), and post‑write audits (counts, sums, referential checks).
Playbooks you can copy
A) Customer duplicates after CRM import
- Export dupes by email/subsidiary → merge into a canonical record.
- Set canonical externalId; mark merged records inactive, keep internalId history.
- Rebuild references (contacts/addresses) to point at the canonical record.
B) Sales Orders duplicated on retries
- Add idempotency key = hash(customerId + orderNumber + total + date).
- Convert create calls to upsert using externalId.
- Retries must be GET‑before‑POST to prevent re‑inserts.
C) Invoice sync failing intermittently
- Reduce batch size, add backoff on 429/5xx.
- Ensure mandatory tax/currency fields are mapped; verify posting period is open.
- Observability: log SuiteTax messages and diff amounts line‑by‑line.
When to use a dedicated sync engine
If you need sub‑second, field‑level two‑way sync with dedupe and conflict handling, a platform like Stacksync helps:
- Real‑time, bi‑directional sync across NetSuite, CRMs, DBs.
- Idempotency + conflict resolution built‑in; referential integrity for parent/child records.
- Intermediate DB option to normalize schemas; SQL access for validation.
- Alerts, rollback, and retries handled centrally.
Copy‑paste checklist
- Freeze writes, pick source of truth per object.
- Export & merge duplicates; preserve history.
- Enforce externalId everywhere.
- Convert creates to upserts.
- Add idempotency keys.
- Order parent→child operations.
- Backoff + bounded retries.
- Turn on duplicate detection rules.
- Add logs/alerts with requestId & externalId.
- Pilot in sandbox; promote gradually.
Next steps
If you’re firefighting duplicates today or planning a clean, bi‑directional NetSuite sync, evaluate Stacksync for real‑time upserts, idempotent retries, and schema‑aware conflict resolution. Book a short demo and see how teams eliminate duplicate SO/Invoices while cutting integration toil.
FAQs
Is internalId safe to use for matching?
No. Use externalId that is stable across systems; keep internalId for NetSuite internals only.
How do I stop webhook replays from duplicating records?
Require an idempotency header/key and store it server‑side for 24–72 hours.
What if I must support multi‑subsidiary customers?
Include subsidiary in your match key or use a composite externalId; avoid global email‑only matching.
Do I need CDC?
If you expect near real‑time accuracy and lower API thrash, yes—CDC beats polling.