Introduction
A field service organization running Zuper for job management and NetSuite as its accounting system already had a scheduled, one-way invoice transfer moving completed jobs into NetSuite. The next step was to extend that foundation into a fully bidirectional integration, so that everything happening to an invoice or a part after the first transfer — amendments, cancellations, credit notes, payments and stock movements — stayed aligned across both platforms. This case study covers that extended scope.
Problem Statement
The core sync moved invoices from Zuper into NetSuite, but nothing after that initial transfer was connected. When an invoice was amended or cancelled in Zuper, when a credit note was raised, or when a customer payment was applied in NetSuite, the other system never heard about it. Parts availability lived only in NetSuite, so field technicians had no reliable view of stock. Finance was left reconciling changes by hand, and every manual touch carried the risk of a duplicate posting, a mismatched status or a write into an already-closed accounting period.
Solution
We designed an extended, event-driven integration built on the link established at the first transfer — the NetSuite internal ID stored on the Zuper invoice and the invoice number custom field stored on the NetSuite record. Every flow carries an origin flag so an update written by the integration never triggers the opposite flow, and any operation that would touch a closed period is held for finance rather than forced through.
Invoice Update Sync
Amendments to an already-synced Zuper invoice update the linked NetSuite invoice in place — but only while it is open, unpaid and in an open period.
Cancellation & Void Sync
A cancelled Zuper invoice is voided in NetSuite when eligible, or routed to finance as a proposed credit memo when it is paid or in a closed period.
Credit Memo & Refund Sync
A credit note raised in Zuper creates a matching NetSuite credit memo, applied to the original invoice against the same customer and subsidiary.
Payment Sync
Payments applied in NetSuite write amount paid, balance due and payment date back to the Zuper invoice, setting it to Partially Paid or Paid.
Inventory Sync
Item master, stock levels, parts consumption, returns and transfers move between the systems, keeping NetSuite as the system of record.
Warranty & New Categories
New job categories such as warranty are absorbed through configurable qualification rules — a config change, not a redevelopment.
Attachment Sync
Files held against a Zuper invoice are pushed into the NetSuite file cabinet and attached to the corresponding invoice record.
Historical Backfill
A one-time, batched transfer of pre-go-live invoices, validated against master data and reconciled by subsidiary and period.
On-Demand Execution
The workflow can be run manually alongside the daily schedule, so a single fixed invoice can be reprocessed without waiting for the next run.
How It Works
Every extended flow builds on the same shared link and a common set of guardrails established at initial transfer:
- A change event — an edit, cancellation, credit note, payment or stock movement — is received and the linked record is located using the stored identifier.
- The target record is checked for eligibility before anything is written, so paid invoices and closed periods are never silently overwritten.
- Eligible changes are applied in place; ineligible ones raise an exception naming the record and the blocking condition.
- An origin flag is set on the write so the receiving system does not fire the opposite flow, preventing circular updates.
- Every action is written to a shared run log, tagged with the capability reference, so each flow is traceable rather than failing silently.
Invoice updates are a good example of the eligibility model in action: an open, unpaid invoice in an open period is updated in place, while a partially or fully paid invoice, a closed period or an already-voided invoice is held and reported for finance review instead of being forced through.
Implementation
Implementation began by mapping the Zuper invoicing and approval workflow against NetSuite's contact, item, tax, subsidiary and period structures, so every field had a clear source and destination before development started. Duplicate checks, status mapping and loop prevention were built as configurable rules rather than fixed values, which is what lets new job categories and status changes be absorbed later without rework.
Payment information was scoped to flow one way only — from NetSuite into Zuper — since payments are never created in NetSuite by the integration itself. For inventory, warehouse, van-stock and location codes are mapped one-to-one before the flow is enabled, NetSuite stays the system of record for quantity and valuation, and parts consumption posts at job completion rather than at assignment so unused parts are never deducted. The extended flows are switched on only once the core sync is live and stable in production.
Results & Achievements
The extended integration turned a one-way feed into a connected, two-way financial and inventory picture across both systems:
Fully Bidirectional
Invoice edits, cancellations, credit memos, payments and status changes now move in both directions automatically.
Real-Time Parts Visibility
Field technicians see on-hand stock in Zuper, while NetSuite remains the source of truth for inventory valuation.
Finance-Safe by Design
Paid invoices and closed periods are held for review, never overwritten, keeping the accounting audit trail clean.
No Duplicates or Loops
Stored identifiers and an origin flag stop records being created twice or bouncing endlessly between systems.
Conclusion
RethinkingWeb extended a scheduled Zuper-to-NetSuite invoice transfer into a fully bidirectional invoice and inventory integration — syncing updates, cancellations, credit memos, payments and stock movements while protecting paid invoices, closed periods and against duplicates. The result keeps field and finance teams working from one agreed picture, with new job categories added through configuration rather than code.