# CFO and CMO Dialogue: Ad Spend Read in Gross Margin, Not in a Pixel ### Context and participants * **Participant 1: Mark Vance (Chief Financial Officer, PE-backed industrial and wholesale distribution platform).** Will not approve another quarter of digital ad spend unless each campaign click reconciles to a posted NetSuite Sales Order, Cash Sale or Invoice net of landed cost. * **Participant 2: Claire Sterling (VP of Commercial Growth and Marketing).** Pays an agency retainer for static banners while roughly 1,800 SKUs sit in the NetSuite item master with white-background warehouse photos and nothing else. * **Participant 3: Marcus Cole (Chief Operating Officer).** Carries two lots past 90 days on the shelf (LOT-2026-01B, LOT-2026-02C) that he wants sold before the quarter closes, and wants ads to stop the moment a SKU reaches safety stock. * **Participant 4: Kyle Castor (Founder & Principal Architect, DataOngoing).** Answers in NetSuite objects and in what the ledger will show. *This is a modeled composite dialogue. The participants and the company are archetypes, the SKU, lot and dollar figures are illustrative, and nothing in it is a client result. The commercial terms are the published terms of the [NetSuite Digital Marketing & B2B Inventory Bundle](/services/netsuite-digital-marketing-b2b-inventory-bundle/); the mechanisms can be tried in the [bundle simulator](/proof/netsuite-digital-marketing-b2b-inventory-console/), which is scripted output on synthetic identifiers.* ### The dialogue **Mark Vance (CFO):** "Kyle, last quarter we paid an agency retainer and spent $75,000 across Google and the social channels. They presented a 5.2x return on ad spend to the board. When I pulled the general ledger, revenue in those product lines had not moved, and a meaningful share of the clicks went to three SKU families that had been out of stock for two weeks. If we install your bundle, how do you prove, inside NetSuite, what you added after we start?" **Kyle Castor:** "By fixing the baseline before the first impression, and by never reporting a number that does not come from your own transactions. On Day 0 the bundle writes a 90-day baseline into `customrecord_do_dm_campaign_ledger`: trailing revenue, landed cost and realized gross margin by SKU, subsidiary and customer cohort, read from `transaction` and `transactionaccountingline`. That snapshot is the comparison for everything that follows. Once campaigns run, three things happen in your account rather than in a dashboard somewhere else. Every click from Google, Facebook, Instagram, TikTok or YouTube arrives with its click token and the creative asset ID, and the checkout writes them to `custbody_do_dm_click_id` and `custbody_do_dm_channel` on the Estimate, Sales Order, Cash Sale or Invoice it creates. A User Event joins each attributed transaction to its accounting lines, so landed freight, duties and the FIFO lot cost come off before anything is called a return. And the Suitelet shows you post-launch gross profit against the Day-0 baseline, by channel, from those records. The number you take to the board is the one in your ledger. If it does not clear the fee by the published multiple, the 10x fee guarantee applies." **Claire Sterling (VP of Commercial Growth):** "The creative is my bottleneck. Our buyers are on YouTube Shorts, Reels, TikTok and Performance Max, and what we own is a File Cabinet of flat product photos taken on a receiving dock. We do not have a studio and the agency's video quote per SKU is not something I can multiply by 1,800." **Kyle Castor:** "You do not need a studio, because the three things a B2B buyer actually clicks on are already in NetSuite: the units on hand, the dispatch promise and the wholesale tier price. The studio takes the SKU image from the File Cabinet, removes the background and composites it onto a motion stage with the stock count and the price tier read from the item record. It renders 9:16 at 1080x1920 for Reels, TikTok and Shorts in a three-beat cadence: the lead-time pain, then the Available-to-Promise count and pallet price, then the checkout. The same job outputs 1:1 at 1080x1080 for the Facebook and Instagram feeds, 16:9 at 1920x1080 for YouTube in-stream, and Google RSA copy checked to the character limits, fifteen headlines under thirty characters and four descriptions under ninety. When a SKU moves to the aged-lot rule, the variant regenerates with the clearance tier." **Marcus Cole (COO):** "Two scenarios. A distributor buys twelve pallets of IND-VALVE-4402 at 10:15 and clears our available stock. And the two lots in Aisle 4 that have been there since the spring need to move before the quarter ends." **Kyle Castor:** "Both are rules in `customrecord_do_dm_sku_feed_rule`, and the Map/Reduce `do_mr_inventory_omnichannel_sync` enforces them. Each SKU has a floor in `custrecord_do_dm_min_atp_floor`. The job compares `quantityavailable` with that floor every fifteen minutes and again on each Item Fulfillment and Item Receipt. When the pallet order takes ATP below the floor, the SKU's ad groups are paused across all five channels on that cycle, and they resume when stock returns. Not instantly; on the cycle, and the cycle is fifteen minutes or the fulfillment event, whichever comes first. For the aged lots, the same job reads `inventorynumber` age. Past 90 days on the shelf, the SKU switches to the pallet-release video variant and takes a larger share of the budget toward wholesale buyers. The point is to sell the lot at a tier price before Mark has to book the reserve, and the ledger will show whether it did." **Mark Vance (CFO):** "And when a buyer clicks that ad on YouTube, how does it become a NetSuite order without a service rep spending twenty-five minutes typing it in?" **Kyle Castor:** "The ad lands on a checkout that posts to an idempotent RESTlet, `do_rl_b2b_instant_purchase`. Two paths. Card or ACH: the buyer picks the case or pallet tier, pays, and the RESTlet creates the Cash Sale or Sales Order with the lot assigned on the `inventoryassignment` subrecord. Approved account with a PO: the buyer enters the PO number, the RESTlet reserves the oldest unexpired FIFO lot for 24 hours and creates a Sales Order that is ready to pick. Either way the click token is on the transaction when it is created, which is what makes the attribution record possible later. What I will not promise is a conversion rate or a lift figure. The offer page carries a simulator, and it is arithmetic on your own spend, baseline and margin inputs with synthetic identifiers. The first real number comes from your ledger ninety days after launch." ### What the bundle changes, and what it does not | Dimension | Agency with a separate cart and pixel reporting | DataOngoing bundle inside NetSuite | | :--- | :--- | :--- | | Attribution standard | Platform-reported conversions, no ledger tie-out | Click token on the Sales Order and Invoice, landed cost joined, gross margin against the Day-0 baseline | | Stocked-out SKUs | Keep spending until someone updates the export | Paused across five channels on the next 15-minute cycle or fulfillment event | | Aged lots | Not visible to the ad account | Clearance variant and a larger budget share after 90 days on the shelf | | Creative | Static photos on a brief-and-approve cycle | 9:16, 1:1 and 16:9 video rendered from the SKU record with character-checked RSA copy | | The order | A quote request a rep re-keys | Sales Order or Cash Sale created by the RESTlet with the FIFO lot reserved | | Commercial terms | Retainer plus a share of spend | $15,000 flat setup, $2,500 per month, 10x fee guarantee measured in the ledger | *The outcome column describes mechanisms and published terms, not measured results; the dialogue is a modeled composite.*