← All case studies

Case study · Jul 2026 – Oct 2026

The Jockey Club: Coupa and NetSuite, connected end to end through Celigo.

A bidirectional source-to-pay integration I designed, built and took live as architect and lead developer: 24 Celigo flows covering suppliers, chart of accounts, invoices, payments, expenses and budgets across nine group entities.

Racecourses & events Source-to-pay Coupa Celigo 9 group entities Architect & lead developer
24
Celigo flows in production
9
Group entities
~159,000
GL combinations provisioned in Coupa
1.28M
API operations per full chart-of-accounts walk

1The challenge

The Jockey Club runs procurement, supplier onboarding, invoicing and expenses in Coupa, and its ledger in NetSuite OneWorld across nine group entities. The two systems needed to work as one source-to-pay process: suppliers created once and paid only when Finance is satisfied, spend coded only to combinations NetSuite will accept, and every invoice, credit, payment, expense and budget landing in the right subsidiary.

Across nine entities that left no room for shortcuts: no hard-coded crosswalks to maintain, no duplicate postings when a run is retried, and a way for Finance and support to see the health of every flow without logging in to Celigo.

2The approach

Celigo integrator.io carries the data; NetSuite holds the rules. Every flow uses JavaScript hooks, lookups and filters, and every flow is idempotent by design, so a re-run updates rather than duplicates.

Integration map: Coupa on the left and NetSuite OneWorld on the right, connected through Celigo integrator.io by six flow families: suppliers (flows 01 to 03C), chart of accounts (04 family), invoices and credits (07), payments (08a, 08b, 09), expenses (05, 06) and budgets (11, 11B).
Six flow families, 24 flows. Suppliers, chart of accounts, invoices and credits, payments, expenses and budgets, each with its own direction and controls. Select the image to view it full size.

On the NetSuite side, ten SuiteScript 2.1 scripts and a set of custom records give the integration its controls, logs and operating console. One house rule ran through the whole build: every integration value lives in a new, purpose-built field. Legacy procurement fields were never reused, so old and new data cannot collide.

3What was built

Supplier onboarding, gated by Finance

A new supplier never becomes payable until Finance has verified the bank details in NetSuite. Celigo moves the record between the two systems at each step (flows 01, 01B, 01C, 01D, 02, 03 and 03C).

  • An approved Coupa Supplier Information record creates the NetSuite vendor, held Inactive and Pending Approval with Bank Details Changed until Finance signs off through the existing approval workflow.
  • Remit-to addresses and tax registrations are pushed to the Coupa supplier, and remit-to accounts land as NetSuite Electronic Bank Payments bank-detail records in primary and secondary payment-file formats.
  • Fingerprint-based change detection re-flags the vendor for Finance verification on any bank change, and retired accounts are deactivated.
  • Once Finance approves, Celigo activates the Coupa supplier, defaults the SRP tax code for GB suppliers, marks the supplier and SIM exported, and mirrors the live Coupa status back to NetSuite.
  • Multi-subsidiary vendors: Coupa legal entities are crosswalked to NetSuite subsidiaries and stamped back onto the Coupa supplier as chart-of-accounts and content-group visibility. Supplier edits sync in both directions with echo-loop and convergence guards.
Swimlane diagram across Coupa, NetSuite and Finance: supplier information approved in Coupa, vendor created and held in NetSuite, remit-to and VAT pushed to Coupa, bank details landed in NetSuite, Finance verifies and approves, supplier activated in Coupa, and live status mirrored back to NetSuite.
Seven steps from approval to payable. After go-live, a bank change, a supplier edit in Coupa or a new subsidiary in NetSuite keeps both systems aligned.

Chart of accounts in Coupa, generated from NetSuite

About 159,000 valid GL combinations across nine entities are provisioned in Coupa as a six-level billing-string hierarchy — Entity › Account › Location › Event Type › Department › Event Space — so users can only code spend to combinations NetSuite accepts.

  • Full walk (04F) — walks every valid combination, creating missing nodes and re-stamping labels: 1.28 million API operations per run, with every error classified.
  • Daily delta (04) — new and changed GL validation records reach Coupa the same day.
  • Fast deactivation (04D) and orphan sweep (04A) — combinations NetSuite no longer accepts are switched off in Coupa, with a monthly backstop for anything left behind.
  • Golden-record canary (04C) — a known combination is checked first, so a change to the segment order stops the run before it can do damage.
  • NetSuite is the source of truth — GL validation records are read through a saved search; labels follow NetSuite and Coupa-side renames are overwritten.
A sample billing string ENT.6200.L03.ET05.FIN.888 broken into entity, account, location, event type, department and event space, shown as a parent-child chain in Coupa, alongside the 04 flow family that keeps it in step.
Account first, on purpose. Coupa invoice lines carry the billing string in this order, so the invoice flow parses the same structure on the way back into NetSuite.

Coupa invoices to NetSuite vendor bills

Invoices and credit notes from every entity post to the right subsidiary, vendor and item without a single hard-coded list (flow 07). The Coupa item master is the crosswalk, maintained by the business as data.

  • The subsidiary is resolved from the entity segment of the billing string through its External ID, and the vendor through the Coupa supplier ID.
  • Each line finds its NetSuite item by first match: a Coupa catalogue item, an item number on the line, or an item code in the item master. A line with no match posts as an expense line coded from the billing string, never as an error.
  • Credit notes are matched to the open bill and applied automatically.
  • Posting is idempotent: bills and credits are matched on the Coupa transaction ID, so a retry updates rather than duplicates. NetSuite IDs are written back first and the exported flag second, because Coupa locks exported invoices.
  • Coupa Pay virtual-card invoices post on payment hold until the settlement flow releases them.
  • A 777-invoice backlog was re-imported through the same rules, with every residual error traced to a named data fix.
Six-step flow from an approved Coupa invoice or credit note, through Celigo line normalisation and reference lookups, to a NetSuite vendor bill or credit, credit application, and write-back to Coupa, with the first-match item rules and re-run safeguards.
Built to be re-run safely. Idempotent posting, subsidiary from the data, virtual-card bills held, and the backlog cleared through the same rules.

Payments, expenses and budgets

  • Payments (08a, 08b, 09) — paid status written back to Coupa at applied-line grain, voids and reversals handled, and Coupa Pay virtual-card settlement recorded against each subsidiary's clearing account. A payment sync ledger with composite idempotency keys makes every write-back safe to repeat.
  • Expenses (05, 06) — expense reports post net of VAT with subsidiary-aware expense categories and attendee capture, and expense payments are written back to Coupa.
  • Budgets (11, 11B) — budget lines flow from SuiteAnalytics Connect to Coupa, consumption and drift come back to NetSuite, and NetSuite-side changes post as audited adjustments.

What was built inside NetSuite

Ten SuiteScript 2.1 scripts and six custom records, all promoted from sandbox to production through staged SuiteBundler bundles.

  • The Integration Control Centre (Suitelet), an integration log writer (RESTlet) and a scheduled alerter that flags failing or stale flows.
  • An amortisation User Event that sets schedules on bill and credit lines from the event date, whatever the entry path.
  • Remit and tax change detection that raises the flag only on genuine value changes, and an attendee popup on the expense report.
  • A Coupa supplier ID backfill (Map/Reduce) that runs as a dry run by default and writes a CSV audit of every change.
  • Custom records for the payment sync ledger, supplier event log, expense attendees, GL deactivation log, budget configuration, and the integration run log and errors behind the Control Centre.
Inventory of the NetSuite build: ten SuiteScript 2.1 scripts with their script types, six custom records, and the custom fields and saved searches on vendors and transactions.
House rule. Every integration value lives in a new, purpose-built field, so legacy procurement data and integration data never collide.

4The Integration Control Centre

A NetSuite Suitelet, built in SuiteScript 2.1, that gives Finance and support one view of every Celigo flow — run health, a register of every production flow, and error triage with a suggested fix — without logging in to Celigo.

Screens on this page are illustrative recreations with sample data.

5Taking it live

  • Owned end to end: design and build, UAT remediation, production migration and go-live.
  • Production migration through staged SuiteBundler bundles, plus a Node.js tool that converts the sandbox Celigo build for production with fail-closed validation.
  • An Integration Requirements Document for Coupa's move-to-production review, with runbooks, SIT scripts and reconciliation searches for Finance and support.

6The outcome

Finance controls who gets paid

No supplier becomes payable until Finance has verified its bank details in NetSuite, and any later bank change sends it back for verification.

Spend coded right first time

Coupa users can only choose GL combinations NetSuite accepts, kept in step daily and checked by a full walk.

No hard-coded crosswalks

Subsidiaries, vendors and items resolve from data, so new entities and items need no code change.

Safe to re-run

Idempotent posting and a sync ledger with composite keys mean a retry updates rather than duplicates.

One view for Finance and support

The Integration Control Centre shows every flow's health and every error with a suggested fix, inside NetSuite.

A clean go-live

Staged bundles and a fail-closed promotion tool took the build to production, and a 777-invoice backlog was re-imported through the same rules.

7Technologies used

Celigo integrator.ioCoupaNetSuite OneWorldSuiteScript 2.1SuiteletsRESTletsMap/ReduceUser EventClient ScriptScheduled scriptsCustom recordsSaved searchesSuiteAnalytics ConnectElectronic Bank PaymentsSuiteBundlerNode.jsJavaScript hooks
"Finance should never have to open Celigo to know whether the integration is healthy. Every flow, every error and every fix is visible inside NetSuite, and no supplier gets paid until Finance says so."
Raja Saqib
Architect and lead developer on The Jockey Club integration

Need a similar outcome?

Whether it's Coupa, Celigo or any other NetSuite integration — let's talk it through.

Book a free 30-minute call