Skip to content

Integration  ·  Revenue operations

How to build a CPQ to ERP sync

Finance adds a SKU on Monday, sales quotes it on Tuesday, and the order fails on Wednesday because the mapping table has never heard of it. The thinking behind a sync that holds, the prompts that build it, and what it takes to keep it running.

Built with Tray Headless

  1. System Salesforce CPQ
  2. Step Mapping table
  3. Step Ramp as periods
  4. System NetSuite
Also Unmapped stops

Each ramp period becomes its own line, and an unmapped SKU blocks rather than falling through to a default.

The short answer

What is a CPQ to ERP sync?

A CPQ to ERP sync is four parts: a product mapping held as data instead of in code, ramp and proration structures carried through intact instead of flattened to a single figure, catalogue alignment that runs in both directions, and a hard failure on an unmapped SKU rather than a guess. The mistake that costs most is flattening the ramp. A three year deal with escalating pricing booked as one annual figure is wrong in year two and wrong for the renewal.

What matters here

  • Hold the product mapping as data. The catalogue changes monthly and the integration should not need republishing when it does.
  • Never flatten a ramp. A deal with escalating pricing booked as one figure is wrong from year two onward and corrupts the renewal.
  • Reconcile the catalogues both ways. A SKU in CPQ that the ERP has never heard of is a booking failure waiting for a quarter end.
  • Fail loudly on an unmapped SKU. A guess produces revenue booked against the wrong account, and that is found by audit rather than by you.
  • Carry the CPQ line id onto the ERP line. Without it, reconciliation compares totals instead of lines and misses the offsetting errors.

Who this is for

You run revenue operations or finance systems. Quoting and booking use different product catalogues, somebody maintains the mapping in a spreadsheet, and a new SKU takes a week to become quotable.

How it works in practice

What has to happen between a product existing in one catalogue and being bookable in the other.

  1. 1

    A new ERP item appears in the mapping queue

    Detected rather than announced, because the catalogue changes without anybody telling the integration.

  2. 2

    Somebody maps it, once, as data

    A row in a table, not a code change. The mapping is owned by finance systems, not by whoever wrote the workflow.

  3. 3

    Quote lines resolve through the mapping at booking time

    Every line, every time. An unmapped SKU stops the booking rather than falling through.

  4. 4

    Ramps and proration are carried as structure

    Each period is its own line with its own dates and price, not an average across the term.

  5. 5

    The CPQ line id travels onto the ERP line

    So reconciliation compares line to line rather than total to total.

  6. 6

    Both catalogues are reconciled nightly

    Items in one and not the other, in both directions, reported before a deal hits the gap.

What the sync is made of

Two catalogues that will never be identical, and one commercial agreement that has to survive the translation.

Mapping as data

A table keyed on CPQ product code, holding the ERP item, the revenue account and the tax treatment. Editable by finance systems without a deployment.

Ramps carried intact

Multi-year and escalating structures kept as separate periods with their own dates and prices. Flattening is the most common and most expensive shortcut here.

Two-way catalogue alignment

Nightly comparison in both directions, because a SKU added on either side is a booking failure nobody sees coming.

A hard fail on unmapped

No fallback item, no best guess. An unmapped SKU stops the booking and raises it, because the alternative is revenue on the wrong account.

The Tray Headless prompts

Paste these into Claude Code or Codex with the Tray Headless plugin installed. Each stage runs on its own. The systems named in them are the worked example rather than a requirement, and every prompt says so.

Once per project, run /tray-workflows:set-workspace to pick the workspace these build in. Point it at a sandbox first.

  1. 1

    First, pull both catalogues

    The mapping cannot be designed until both sides are visible.

    Headless skills build-workflow

    Use build-workflow. The systems in play are Salesforce CPQ and
    NetSuite, or whatever we run in those seats.
    
    I need the CPQ model: SBQQ__Quote__c, SBQQ__QuoteLine__c and
    SBQQ__Subscription__c, plus Product2 and PricebookEntry, and how ramp
    and subscription pricing are represented across them. From NetSuite I
    need the Item records, their revenue accounts and their tax schedules.
    
    Then show me both catalogues side by side with anything that looks like a
    match already. The differences are the work.
  2. 2

    Build the mapping as a table, not as logic

    Because the catalogue changes more often than the integration will.

    Headless skills build-workflow tray-patterns

    Use build-workflow. Create a mapping table keyed on CPQ product code,
    holding: the NetSuite item id, the revenue account, the tax schedule, the
    income deferral treatment, and whether the item is subscription or
    one-off.
    
    Read it at booking time, every time. Do not compile the mapping into the
    workflow, and do not cache it beyond a few minutes. A new SKU should be
    quotable and bookable the same day somebody maps it.
    
    Detect unmapped items on both sides and put them in a queue for finance
    systems, with everything needed to map them in one screen.
  3. 3

    Carry ramps and proration through as structure

    The step that decides whether year two of a deal is correct.

    Headless skills tray-patterns

    Never flatten a ramp to a single annual figure.
    
    For each ramp period, create a separate ERP line with its own start date,
    end date, quantity and unit price. A three year deal at 100k, 120k and
    140k is three lines, not one line at 120k.
    
    Handle proration explicitly: a mid-month start prorates the first period
    by day count, and the term end aligns to the contract instead of to a
    calendar year. Co-terminated amendments take the parent contract end
    date.
    
    Then assert that the sum of the ERP lines equals the CPQ total to the
    cent. If it does not, stop. A rounding difference across periods is a
    real difference and finance will find it.

    Flattening a ramp is the single most expensive shortcut in this integration. It books correctly in year one, which is why it survives testing.

  4. 4

    Fail loudly on anything unmapped

    Because the alternative is revenue booked against the wrong account.

    Headless skills tray-gotchas

    Use tray-gotchas, then make unmapped a stop condition.
    
    If a quote line has no mapping, the booking stops. No fallback item, no
    default revenue account, no closest match. Raise it to finance systems
    and to the deal desk with the product code and the deal it is blocking.
    
    Also stop on: a price book entry whose currency the ERP is not configured
    for, an item mapped to an inactive ERP record, and a discount that pushes
    a line price below a floor finance has set.
    
    A guess here produces revenue on the wrong account, and that is found in
    an audit instead of by anybody watching.
  5. 5

    Reconcile the catalogues in both directions

    A SKU added on either side is a booking failure waiting for quarter end.

    Headless skills tray-patterns

    Nightly, compare both catalogues and report:
    
      Active CPQ products with no mapping
      Mapped ERP items that have been deactivated
      ERP items with no CPQ equivalent, which is usually fine but worth seeing
      Mappings pointing at a revenue account that no longer exists
      Price book entries in currencies the ERP cannot accept
    
    Alert on the first two, which block bookings. Report the rest.
    
    Also carry the CPQ line id onto every ERP line, so reconciliation can
    compare line to line. Comparing totals hides two errors that offset each
    other, and that pair is exactly what an auditor finds.
  6. 6

    Validate, then hand the table to finance systems

    Because the catalogue belongs to them.

    Run the per-step schema checks and the whole-workflow audit before this
    touches production.
    
    Then open the same workflow in Tray Build so finance systems can maintain
    the mapping table, the revenue accounts and the tax treatments in the
    visual canvas. Every catalogue change touches this, and none of them
    should be an engineering request.

What it connects to

Two catalogues, one mapping, and the people who need to know when they diverge.

Salesforce CPQ

Read products, price books, quote lines and ramp structures with their period dates and prices.

Reads

NetSuite

Read the item master and revenue accounts, and create order lines that mirror the quote structure exactly.

Reads and writes

Salesforce

Write the booking result and any blocking mapping gap onto the opportunity, where the deal team will see it.

Writes

Slack

Tell finance systems about an unmapped SKU immediately, because it is blocking a deal right now.

Writes

Snowflake

Hold the mapping history and the nightly reconciliation, so catalogue drift is visible over time.

Reads and writes

Same build, other stacks

The design does not change if you run something else in one of these seats. The same prompts build it against Microsoft Dynamics 365, SAP S/4HANA, Google BigQuery, Microsoft Teams, HubSpot or Oracle.

Named systems are the ones most teams run, not the only ones that work. Each is an authentication in your Tray workspace, referenced by name, so the workflow never holds a credential. Where we have a connector page, the name links to it.

Running it in production

This decides which revenue account a booking lands on. It is audited every quarter.

It runs where production runs, not on a laptop

Booking-time lookups and the nightly catalogue reconciliation execute on the same engine, with a record of which mapping version produced which line.

Every mapping decision is recorded

Which mapping row resolved which line, and when. That is what makes a revenue misposting traceable, not a mystery.

Credentials are managed, never in code

The ERP credential writes revenue-bearing order lines. It lives in your workspace, scoped tightly, and separately from anything that reads the catalogue.

Finance systems own the table

Mappings, revenue accounts and tax treatments open in Tray Build, maintained by the team that owns the catalogue.

Unmapped blocks, it does not warn

A booking that proceeds on a guess is a misposting. Stopping is the correct behaviour even though it is the noisier one.

Questions people ask

Why hold the mapping as data rather than in code?

Because the product catalogue changes monthly and the integration does not. A new SKU should be bookable the day finance maps it, not the day somebody deploys.

What is wrong with flattening a ramp?

It books correctly in year one, which is why it survives testing, then it is wrong in every subsequent year and it corrupts the renewal figure. Each ramp period needs its own line with its own dates and price.

What should happen to an unmapped SKU?

The booking stops. No fallback item and no closest match, because a guess puts revenue on the wrong account and that surfaces in an audit instead of in a report you read.

Why reconcile the catalogues in both directions?

Because a product added in CPQ that the ERP has never seen blocks a booking, and a deactivated ERP item that is still mapped fails in a different way. Both are found by a nightly comparison and by nothing else.

Can finance systems maintain this without engineering?

Yes. The mapping table, revenue accounts and tax treatments open in Tray Build, so the team that owns the catalogue owns the translation.

Last reviewed September 2026.