Hyperion Partner Compensation Parameters

CRM / NetSuite Replatform · Partner Compensation

Master Partner Parameters
Design & Implementation Guide

Analysis of the Treadstone Commercial Compensation Model against the Hyperion OMNI Partner Agreement (v1 Mar 2024 and v6 Jun 2025) — with a complete field specification for the NetSuite Master Partner Parameters tab and technical steps for PostgreSQL synchronization.

Parameters Covered
14
All core Treadstone parameters confirmed against agreements
Gaps Identified
10
Parameters in agreements not captured by current model
New Exhibit (v6)
D.1
VAST Track — per-unit flat dollar commission, not in Treadstone

Scope of documents reviewed

Treadstone_Commercial_Compensation_Model-v2.docx · Hyperion OMNI-Partner Agreement HYP-OMNI-03212024 (v1) · Hyperion OMNI-Partner Agreement v6-06022025 (v6). The model targets Carrier Activation (Upfront), Residual, and SPIFF categories, which maps to Exhibit A + B of the Partner Agreement. Exhibits C.1, D, D.1, E, and F capture additional revenue streams the model references less specifically.

Section 1

Gap Analysis

The Treadstone model is architecturally sound — its 14 normalized parameters provide a valid framework. However, several contractual parameters in the Partner Agreement either fall between the model's parameters or require more granular sub-fields to be calculable in NetSuite and PostgreSQL.

Core Parameters — Coverage Confirmed

Treadstone ParameterAgreement SourceStatus
PartnerMain Agreement — Partner Information Table✓ Covered
Agreement TypeMain Agreement — Relationship definition✓ Covered
Agreement (effective dates, version, status)Signature block; Exhibit G change requests✓ Covered
Commercial Program / CategoryExhibit A (carrier activation), B (rev share), C.1, D, D.1, E, F✓ Covered
EligibilityExhibit A §2 — deal registration approval; Exhibit B — ESCR eligibility rules✓ Covered
Master Agent / DirectionExhibit A §1 — Hyperion as default Master Agent; bidirectional optional✓ Covered
Revenue SourceExhibit B — carrier; C.1 — customer (HYP paper); D/D.1 — VAST proceeds; E/F — gross revenue✓ Covered
Compensation TypeOne-time (activation, Ex B/C.1/D.1/E/F one-time), recurring (residual, Ex D), milestone (Ex D.1)✓ Covered
Calculation BasisESCR (Ex B); Net Proceeds (Ex C.1/D); Gross Revenue (Ex E/F); flat $ per unit (Ex D.1)✓ Covered
Compensation % / Amount50%/60%/70%/80% (Ex B tiered) or flat 50% (v6); 10% (Ex C.1, D); flat $ (Ex D.1); configurable % (Ex E/F)✓ Covered
Payment TriggerCarrier payment to Hyperion (Ex A §3); customer payment to Hyperion (Ex C.1/D); monthly recognition (Ex D residual)✓ Covered
Recovery / Chargeback RuleExhibit A §7 — withholding and chargeback; 210-day final hold; offset/invoice mechanisms✓ Covered
Exception / OverrideExhibit A §4.5 — Hyperion sole discretion modifications; Exhibit C.1 §15 — custom pricing comp✓ Covered
Source of AuthorityAgreement + active Exhibit(s) + Exhibit G change requests✓ Covered

Gaps — Parameters Missing or Under-Specified

These 10 items exist in the agreements but have no dedicated field in the current Treadstone model

Each gap is described below with its contractual source and recommended NetSuite field action.

#GapAgreement ClauseImpactAction
G1 Active Exhibits (per-partner YES/NO) Each of Exhibits A–H may be included or excluded per partner. The model treats all exhibits as always applicable. Main Agreement — Recitals §D exhibit table; deployment instructions §18 High Add a boolean checkbox per exhibit on the partner record
G2 Commission Structure Type — Tiered vs Flat v1 uses a 6MRA tier system (SELECT/PREMIER/ELITE/TITAN at 50/60/70/80%). v6 primary language uses a flat 50%; v6 also includes the tiered structure as "Alternate Language." Different partners may be on different language versions. Exhibit B §1 (v1 tiered) vs Exhibit B §1 (v6 flat 50% primary + ALTERNATE LANGUAGE tiered) High Add Commission Structure Type field (Tiered | Flat), plus tier threshold and rate fields
G3 SPIFF Exclusion & Separate SPIFF Rate Exhibit B explicitly excludes SPIFFs from the pass-through calculation ("exclusive of spiffs, MDF, co-op"). The model lists SPIFF as a compensation type but doesn't flag that it is NOT passed through via the standard % — it must be tracked and paid separately if at all. Exhibit B §1 — "exclusive of spiffs, MDF, co-op, and other bonuses not directly attributable to Partner" High Add SPIFF Included in Pass-Through boolean (default: No) and separate SPIFF Rate % field
G4 6MRA Tier Tracking Parameters When on tiered Exhibit B, the tier is determined by a 6-month rolling average of ESCR. Partners are eligible beginning the 7th month. Need: tier start date, current 6MRA value, current tier, and tier assignment date. Exhibit B §1.1 (v1) and ALTERNATE LANGUAGE in v6 Medium Add Tier Eligibility Start Date, Current Tier, Current 6MRA ($), Tier Last Updated
G5 Withholding Trigger (300% Rule) Exhibit A §7.3: if a single commission period exceeds 300% of the monthly commission run rate, Hyperion may withhold up to 20% until after the chargeback period expires. This is a specific risk-control rule not captured by the generic "Recovery/Chargeback Rule" parameter. Exhibit A §7.3 (both v1 and v6) Medium Add Withholding Threshold Multiplier (default: 300%), Withholding Hold % (default: 20%)
G6 Final Payment Hold Period (210 days) After termination or expiration, Hyperion holds all compensation for 210 days pending final true-up. This is a concrete operational parameter needed for payment scheduling. Exhibit A §8.2; Exhibit C.1 §3; Exhibit D §6 (all agreements) Medium Add Post-Termination Hold Days (default: 210)
G7 VAST Track — Exhibit D.1 (new in v6) Exhibit D.1 is entirely new in v6. It covers VAST Track products with a per-unit flat dollar commission (not a percentage). The amount is a blank placeholder negotiated per partner. The Treadstone model has no reference to VAST Track. Exhibit D.1 §3.2.1 — "flat dollar amount per device/service sold" (v6 only) High Add VAST Track section: VAST Track Active, VAST Track Commission Amount ($), VAST Track Registration Method
G8 Post-Termination Residual Continuation Flag Exhibit A §6.2: if Hyperion terminates for convenience (§4.2), residual commissions continue flowing to the partner until the Supplier's residual period expires. For all other termination types, compensation stops immediately. This distinction affects payment scheduling after termination. Exhibit A §6.2 vs §6.1; Exhibit D §5 post-termination language Medium Add Post-Termination Residual Continues boolean (set by system based on termination type)
G9 Exhibit E/F Eligible & Ineligible Product Scope Exhibits E and F contain blank fields for eligible products, ineligible products, and applicable commission rates. These are negotiated and left intentionally open in the template. Without capturing these per-partner, the commission calculation engine cannot determine which referrals earn a fee. Exhibit E §2–4; Exhibit F §2–4 (both versions) High Add Exhibit E and F sub-sections with Eligible Products, Ineligible Products, one-time %, recurring % for each direction
G10 Agreement Version / Language Variant Tracking A partner may be on v1 (tiered Exhibit B), v6 flat-rate, or v6 with alternate tiered language. The governing version determines the entire calculation path. The model captures "Agreement" but not the version's impact on which calculation logic applies. HYP-OMNI-01302024 (v1) vs HYP-OMNI-v5-01262025 (v6); Exhibit B alternate language annotation Medium Add Agreement Template Version and Exhibit B Language Variant (Standard Tiered | Flat Rate | Custom)

Section 2

NetSuite — Master Partner Parameters Tab

Complete field specification for the Master Partner Parameters tab on the Partner (Vendor/Customer) form. All fields are implemented as custom fields on either the Partner record or a child custom record linked one-to-one per active agreement.

Implementation approach

Create a Custom Record type called Partner Agreement Parameters (one record per partner agreement) linked via a custom field to the Partner record. This allows version history and amendment tracking. Surface this record in the Master Partner Parameters subtab on the Partner form using a Custom Sublist. The NetSuite internal ID convention used below follows custrecord_hyp_<field>.

Agreement Identification

All Partners
Field NameNS Internal IDTypeOptions / DefaultNotes
Agreement Typecustrecord_hyp_agmt_typeListStrategic Partner | Partner ReferralDetermines which exhibits and calc rules apply
Agreement Template Versioncustrecord_hyp_agmt_tmpl_verListHYP-OMNI-03212024 | HYP-OMNI-v5-01262025 | CustomTracks which template version was used — affects Exhibit B logic (Gap G10)
Agreement Reference / IDcustrecord_hyp_agmt_refTexte.g. HYP-OMNI-ACME-04012024
Effective Datecustrecord_hyp_agmt_eff_dateDate
Expiration Datecustrecord_hyp_agmt_exp_dateDate
Agreement Statuscustrecord_hyp_agmt_statusListActive | Expired | Terminated | Pending | Suspended
Termination Datecustrecord_hyp_agmt_term_dateDateSet when agreement terminates
Termination Typecustrecord_hyp_agmt_term_typeListConvenience (§4.2) | For Cause (§4.4) | Immediate (§4.5) | Non-RenewalDrives post-term residual continuation (Gap G8)
Post-Term Residual Continuescustrecord_hyp_postterm_residualBooleanDefault: NoAuto-set by SuiteScript: Yes only when Termination Type = Convenience (§4.2)
Post-Termination Hold Dayscustrecord_hyp_final_hold_daysIntegerDefault: 210210-day final payment hold (Gap G6)
Bidirectional Enabledcustrecord_hyp_bidirectionalBooleanDefault: NoEnables Exhibit B/E Partner-as-Master-Agent direction

Active Exhibits (Gap G1)

Gap Addressed
Field NameNS Internal IDTypeNotes
Exhibit A Active — Supplier referral termscustrecord_hyp_exh_aBooleanMandatory per agreement; default Yes
Exhibit B Active — Revenue sharecustrecord_hyp_exh_bBooleanMandatory; default Yes
Exhibit C.1 Active — HYP-billed productscustrecord_hyp_exh_c1BooleanOptional
Exhibit D Active — VAST Smart SIMcustrecord_hyp_exh_dBooleanOptional
Exhibit D.1 Active — VAST Track New v6custrecord_hyp_exh_d1BooleanOptional; v6 only — hide on v1 template forms
Exhibit E Active — HYP-generated leadcustrecord_hyp_exh_eBooleanOptional
Exhibit F Active — Partner-generated leadcustrecord_hyp_exh_fBooleanOptional
Exhibit H Active — Master Services Agreementcustrecord_hyp_exh_hBooleanOptional

Exhibit B — Carrier Revenue Share (Upfront / Residual)

Gaps G2, G3, G4, G5
Field NameNS Internal IDTypeOptions / DefaultNotes
Commission Structure Typecustrecord_hyp_b_structListTiered (6MRA) | Flat Rate | CustomGap G2 — drives which calc path is used
Exhibit B Language Variantcustrecord_hyp_b_langListStandard Tiered (v1) | Flat Rate Primary (v6) | Alt Tiered (v6)Gap G10
Flat Rate Pass-Through %custrecord_hyp_b_flat_pctPercentDefault: 50Active when Structure = Flat Rate; v6 default
SELECT Tier Rate %custrecord_hyp_b_tier_selectPercentDefault: 50Active when Structure = Tiered; 6MRA < $7,500
PREMIER Tier Rate %custrecord_hyp_b_tier_premierPercentDefault: 606MRA $7,500–$37,499
ELITE Tier Rate %custrecord_hyp_b_tier_elitePercentDefault: 706MRA $37,500–$149,999
TITAN Tier Rate %custrecord_hyp_b_tier_titanPercentDefault: 806MRA ≥ $150,000
Current Tiercustrecord_hyp_b_cur_tierListSELECT | PREMIER | ELITE | TITANGap G4 — updated monthly by scheduled script
Tier Eligibility Start Datecustrecord_hyp_b_tier_startDate7th month after agreement execution; Gap G4
Current 6MRA ($)custrecord_hyp_b_6mraCurrencyCalculated field updated by scheduled script; Gap G4
Tier Last Evaluatedcustrecord_hyp_b_tier_eval_dtDateDate of last tier assignment; Gap G4
SPIFF Included in Pass-Throughcustrecord_hyp_b_spiff_passthruBooleanDefault: NoGap G3 — Exhibit B explicitly excludes SPIFFs
SPIFF Rate % (if separate)custrecord_hyp_b_spiff_ratePercentGap G3 — applicable only when SPIFFs paid separately
Withholding Threshold Multipliercustrecord_hyp_b_withhold_threshPercentDefault: 300Gap G5 — Exhibit A §7.3: if period ESCR ≥ X% of run rate, withhold applies
Withholding Hold %custrecord_hyp_b_withhold_pctPercentDefault: 20Gap G5 — % of commission withheld pending chargeback period
Minimum Commission Period ($)custrecord_hyp_b_min_pmtCurrencyExhibit A §3.8 — no payment obligation if amount below threshold (check agreement)

Exhibit C.1 — HYP-Billed Products / Services Referral

Optional Exhibit
Field NameNS Internal IDTypeDefaultNotes
C.1 Referral Fee %custrecord_hyp_c1_fee_pctPercent1010% of Net Sales Proceeds
C.1 Calculation Basiscustrecord_hyp_c1_basisListNet ProceedsGross minus taxes, shipping, fees, processing
C.1 Payment Terms (days)custrecord_hyp_c1_pay_termsInteger30Net-30 from HYP acceptance of partner invoice
C.1 Custom Comp Notecustrecord_hyp_c1_custom_noteText AreaExhibits §15 — custom % for discounted SRP transactions

Exhibit D / D.1 — VAST (Smart SIM + Track)

Exhibit D.1 is Gap G7
Field NameNS Internal IDTypeDefaultNotes
VAST SIM Commission %custrecord_hyp_d_sim_pctPercent10Exhibit D §3.3.1 — 10% of VAST Proceeds (recurring)
VAST SIM Discounted Ratecustrecord_hyp_d_sim_disc_pctPercentCustom rate for discounted SIM; left blank until agreed
VAST Track Active v6custrecord_hyp_d1_activeBooleanNoGap G7
VAST Track Commission Amount ($)custrecord_hyp_d1_flat_amtCurrencyGap G7 — per-unit flat dollar; negotiated blank in template
VAST Track Registration Methodcustrecord_hyp_d1_reg_methodListDiscount CodeDiscount Code | Registered Lead (Exhibit D.1 §1.1)

Exhibit E & F — Bidirectional Referral Commissions

Gap G9 Addressed
Field NameNS Internal IDTypeNotes
Exhibit E — One-Time Commission % (to HYP)custrecord_hyp_e_onetime_pctPercent% of Gross Revenue; blank in template — fill at signing
Exhibit E — Recurring Commission % (to HYP)custrecord_hyp_e_recur_pctPercent% of Gross Revenue for MRC transactions
Exhibit E — Eligible Productscustrecord_hyp_e_elig_prodText AreaPartner products/services in scope; blank in template
Exhibit E — Ineligible Productscustrecord_hyp_e_inelig_prodText AreaExclusions
Exhibit F — One-Time Commission % (to Partner)custrecord_hyp_f_onetime_pctPercent% of Gross Revenue; blank in template — fill at signing
Exhibit F — Recurring Commission % (to Partner)custrecord_hyp_f_recur_pctPercent% of Gross Revenue for MRC transactions
Exhibit F — Eligible Productscustrecord_hyp_f_elig_prodText AreaHYP products/services in scope
Exhibit F — Ineligible Productscustrecord_hyp_f_inelig_prodText AreaExclusions

Exception / Override Parameters

All Partners
Field NameNS Internal IDTypeNotes
Exception Appliescustrecord_hyp_exc_activeBooleanTriggers display of exception sub-fields
Exception Typecustrecord_hyp_exc_typeListPartner-Level | Deal/Opportunity | Inside Seller
Exception Authorized Bycustrecord_hyp_exc_authTextName/role of approver
Exception Effective Datecustrecord_hyp_exc_eff_dateDate
Exception Expiry Datecustrecord_hyp_exc_exp_dateDate
Exception Notescustrecord_hyp_exc_notesText AreaDescribe deviation from standard terms

Section 3

PostgreSQL Schema

The PostgreSQL database stores the authoritative compensation parameters (synced from NetSuite) and performs all compensation calculations. NetSuite is the system of record for parameters; PostgreSQL is the calculation and payment engine.

-- ============================================================
-- HYPERION PARTNER COMPENSATION — PostgreSQL Schema
-- ============================================================

-- Partners (master record, synced from NetSuite Partner/Vendor)
CREATE TABLE partners (
  partner_id          UUID         PRIMARY KEY DEFAULT gen_random_uuid(),
  ns_internal_id      INTEGER      UNIQUE NOT NULL,   -- NetSuite internalid
  entity_name         TEXT         NOT NULL,
  legal_address       TEXT,
  status              TEXT         NOT NULL DEFAULT 'active',
  created_at          TIMESTAMPTZ  DEFAULT now(),
  updated_at          TIMESTAMPTZ  DEFAULT now()
);

-- Partner Agreement Parameters (one row per active agreement)
CREATE TABLE partner_agreement_params (
  param_id                   UUID         PRIMARY KEY DEFAULT gen_random_uuid(),
  partner_id                 UUID         REFERENCES partners(partner_id) ON DELETE CASCADE,
  ns_record_id               INTEGER      UNIQUE,       -- NS custom record internalid

  -- Agreement identification
  agreement_type             TEXT         NOT NULL,     -- 'strategic_partner' | 'partner_referral'
  agreement_template_ver     TEXT,
  agreement_reference        TEXT,
  effective_date             DATE,
  expiration_date            DATE,
  agreement_status           TEXT         DEFAULT 'active',
  termination_date           DATE,
  termination_type           TEXT,
  postterm_residual_continues BOOLEAN     DEFAULT false,
  postterm_hold_days         INTEGER      DEFAULT 210,
  bidirectional_enabled      BOOLEAN      DEFAULT false,

  -- Active exhibits
  exhibit_a_active   BOOLEAN DEFAULT true,
  exhibit_b_active   BOOLEAN DEFAULT true,
  exhibit_c1_active  BOOLEAN DEFAULT false,
  exhibit_d_active   BOOLEAN DEFAULT false,
  exhibit_d1_active  BOOLEAN DEFAULT false,  -- v6 only
  exhibit_e_active   BOOLEAN DEFAULT false,
  exhibit_f_active   BOOLEAN DEFAULT false,
  exhibit_h_active   BOOLEAN DEFAULT false,

  -- Exhibit B — carrier revenue share
  b_commission_struct      TEXT,         -- 'tiered' | 'flat' | 'custom'
  b_lang_variant           TEXT,
  b_flat_rate_pct          NUMERIC(5,2), -- e.g. 50.00
  b_tier_select_pct        NUMERIC(5,2) DEFAULT 50,
  b_tier_premier_pct       NUMERIC(5,2) DEFAULT 60,
  b_tier_elite_pct         NUMERIC(5,2) DEFAULT 70,
  b_tier_titan_pct         NUMERIC(5,2) DEFAULT 80,
  b_current_tier           TEXT,         -- 'SELECT' | 'PREMIER' | 'ELITE' | 'TITAN'
  b_tier_elig_start_date   DATE,
  b_current_6mra           NUMERIC(12,2),
  b_tier_last_evaluated    DATE,
  b_spiff_in_passthru      BOOLEAN       DEFAULT false,
  b_spiff_rate_pct         NUMERIC(5,2),
  b_withhold_thresh_mult   NUMERIC(5,2)  DEFAULT 300, -- 300% trigger
  b_withhold_hold_pct      NUMERIC(5,2)  DEFAULT 20,
  b_min_payment_amt        NUMERIC(12,2),

  -- Exhibit C.1 — HYP-billed products
  c1_fee_pct               NUMERIC(5,2)  DEFAULT 10,
  c1_basis                 TEXT          DEFAULT 'net',
  c1_payment_terms_days    INTEGER       DEFAULT 30,
  c1_custom_note           TEXT,

  -- Exhibit D — VAST Smart SIM
  d_sim_pct                NUMERIC(5,2)  DEFAULT 10,
  d_sim_discounted_pct     NUMERIC(5,2),

  -- Exhibit D.1 — VAST Track (v6)
  d1_flat_commission_amt   NUMERIC(12,2),
  d1_reg_method            TEXT,         -- 'discount_code' | 'registered_lead'

  -- Exhibit E — HYP-generated lead (commission to HYP)
  e_onetime_pct            NUMERIC(5,2),
  e_recurring_pct          NUMERIC(5,2),
  e_eligible_products      TEXT,
  e_ineligible_products    TEXT,

  -- Exhibit F — Partner-generated lead (commission to Partner)
  f_onetime_pct            NUMERIC(5,2),
  f_recurring_pct          NUMERIC(5,2),
  f_eligible_products      TEXT,
  f_ineligible_products    TEXT,

  -- Exception / override
  exception_active         BOOLEAN       DEFAULT false,
  exception_type           TEXT,
  exception_authorized_by  TEXT,
  exception_eff_date       DATE,
  exception_exp_date       DATE,
  exception_notes          TEXT,

  -- Sync bookkeeping
  ns_last_modified         TIMESTAMPTZ,
  pg_synced_at             TIMESTAMPTZ   DEFAULT now(),
  sync_version             INTEGER       DEFAULT 1
);

-- Audit trail for all parameter changes
CREATE TABLE parameter_audit_log (
  log_id         UUID        PRIMARY KEY DEFAULT gen_random_uuid(),
  param_id       UUID        REFERENCES partner_agreement_params(param_id),
  changed_at     TIMESTAMPTZ DEFAULT now(),
  changed_by     TEXT,        -- 'netsuite_sync' | 'manual' | 'scheduled_script'
  field_name     TEXT        NOT NULL,
  old_value      TEXT,
  new_value      TEXT,
  source_ref     TEXT        -- NS record ID or change order ref
);

-- Compensation calculations (results, not parameters)
CREATE TABLE compensation_calculations (
  calc_id           UUID         PRIMARY KEY DEFAULT gen_random_uuid(),
  partner_id        UUID         REFERENCES partners(partner_id),
  param_id          UUID         REFERENCES partner_agreement_params(param_id),
  commission_period DATE         NOT NULL,  -- first day of month
  exhibit           TEXT         NOT NULL,  -- 'B' | 'C1' | 'D' | 'D1' | 'E' | 'F'
  carrier           TEXT,
  gross_revenue     NUMERIC(14,2),
  net_revenue       NUMERIC(14,2),
  escr              NUMERIC(14,2),
  applied_rate_pct  NUMERIC(5,2),
  applied_tier      TEXT,
  comp_type         TEXT,         -- 'upfront' | 'residual' | 'spiff' | 'vast' | 'referral'
  gross_comp        NUMERIC(14,2),
  withholding_amt   NUMERIC(14,2) DEFAULT 0,
  chargeback_offset NUMERIC(14,2) DEFAULT 0,
  net_payable       NUMERIC(14,2),
  payment_status    TEXT          DEFAULT 'pending',
  calculated_at     TIMESTAMPTZ   DEFAULT now()
);

-- Index for common queries
CREATE INDEX idx_calc_partner_period
  ON compensation_calculations(partner_id, commission_period);
CREATE INDEX idx_params_ns_id
  ON partner_agreement_params(ns_record_id);

Section 4

Sync Architecture — NetSuite ↔ PostgreSQL

Parameters are authored and governed in NetSuite (source of record). PostgreSQL receives them via a push-on-save mechanism and a nightly reconciliation batch. Calculations flow in the opposite direction for visibility in NetSuite.

Data Flow Diagram
NetSuite
Partner Record
Custom Record
System of Record
for Parameters
UserEvent
AfterSubmit
(SuiteScript 2.x)
Sync API
Node.js / Python
REST Microservice
Transformation
+ Validation
HTTPS POST
with HMAC
auth
PostgreSQL
partner_agreement
_params
Calculation Engine
+ History
← Nightly reconciliation batch (Scheduled Script) | ← Calculation results pushed back to NS custom fields →

Option A — Push on Save (Recommended for real-time)

A SuiteScript 2.x UserEvent Script fires after any save of the Partner Agreement Parameters custom record. It calls a RESTlet (deployed on NetSuite) or an external HTTPS endpoint that writes to PostgreSQL.

// SuiteScript 2.x — UserEvent AfterSubmit
// File: hyp_ue_partner_params_sync.js

define(['N/https', 'N/record', 'N/log'], function(https, record, log) {
  function afterSubmit(context) {
    if (context.type === context.UserEventType.DELETE) return;

    var rec = context.newRecord;
    var payload = {
      ns_record_id:             rec.id,
      partner_ns_id:            rec.getValue('custrecord_hyp_partner'),
      agreement_type:           rec.getValue('custrecord_hyp_agmt_type'),
      agreement_template_ver:   rec.getValue('custrecord_hyp_agmt_tmpl_ver'),
      agreement_reference:      rec.getValue('custrecord_hyp_agmt_ref'),
      effective_date:           rec.getValue('custrecord_hyp_agmt_eff_date'),
      exhibit_b_active:         rec.getValue('custrecord_hyp_exh_b'),
      b_commission_struct:      rec.getValue('custrecord_hyp_b_struct'),
      b_flat_rate_pct:          rec.getValue('custrecord_hyp_b_flat_pct'),
      b_current_tier:           rec.getValue('custrecord_hyp_b_cur_tier'),
      b_spiff_in_passthru:      rec.getValue('custrecord_hyp_b_spiff_passthru'),
      b_withhold_thresh_mult:   rec.getValue('custrecord_hyp_b_withhold_thresh'),
      b_withhold_hold_pct:      rec.getValue('custrecord_hyp_b_withhold_pct'),
      exhibit_d1_active:        rec.getValue('custrecord_hyp_exh_d1'),
      d1_flat_commission_amt:   rec.getValue('custrecord_hyp_d1_flat_amt'),
      // ... all other fields ...
      ns_last_modified:         new Date().toISOString()
    };

    var response = https.post({
      url:     'https://your-sync-api.internal/api/partner-params/upsert',
      body:    JSON.stringify(payload),
      headers: {
        'Content-Type':  'application/json',
        'Authorization': 'Bearer ' + runtime.getCurrentScript()
                          .getParameter('custscript_hyp_sync_token')
      }
    });

    log.audit('ParamSync', 'Status ' + response.code + ' for record ' + rec.id);
    if (response.code !== 200) {
      log.error('SyncFailed', response.body);
      // Queue for retry via custom record
    }
  }
  return { afterSubmit: afterSubmit };
});

Sync API — Upsert Endpoint (Node.js/Express example)

// POST /api/partner-params/upsert
// Receives NS payload, transforms, upserts into PostgreSQL

app.post('/api/partner-params/upsert', verifyHmac, async (req, res) => {
  const p = req.body;
  const sql = `
    INSERT INTO partner_agreement_params (
      ns_record_id, partner_id, agreement_type, agreement_template_ver,
      effective_date, exhibit_b_active, b_commission_struct, b_flat_rate_pct,
      b_current_tier, b_spiff_in_passthru, b_withhold_thresh_mult,
      b_withhold_hold_pct, exhibit_d1_active, d1_flat_commission_amt,
      ns_last_modified, pg_synced_at
    )
    VALUES ($1, (SELECT partner_id FROM partners WHERE ns_internal_id=$2),
            $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, now())
    ON CONFLICT (ns_record_id) DO UPDATE SET
      agreement_type         = EXCLUDED.agreement_type,
      b_flat_rate_pct        = EXCLUDED.b_flat_rate_pct,
      b_current_tier         = EXCLUDED.b_current_tier,
      b_withhold_thresh_mult = EXCLUDED.b_withhold_thresh_mult,
      exhibit_d1_active      = EXCLUDED.exhibit_d1_active,
      d1_flat_commission_amt = EXCLUDED.d1_flat_commission_amt,
      ns_last_modified       = EXCLUDED.ns_last_modified,
      pg_synced_at           = now(),
      sync_version           = partner_agreement_params.sync_version + 1
    RETURNING param_id, sync_version`;
  await db.query(sql, [p.ns_record_id, p.partner_ns_id, p.agreement_type, ...]);
  await logAuditDiff(p);  // write field-level diffs to parameter_audit_log
  res.json({ ok: true });
});

Option B — Nightly Reconciliation Batch (Safety net)

A NetSuite Scheduled Script runs nightly and exports all custrecord_hyp_partner_params records modified since last sync. This catches any saves that missed the UserEvent push (e.g., CSV imports, bulk updates).

// SuiteScript 2.x Scheduled Script — nightly delta export
// Runs at 2 AM; queries NS saved search, pushes deltas to PG

define(['N/search', 'N/https'], function(search, https) {
  function execute(context) {
    var s = search.create({
      type: 'customrecord_hyp_partner_params',
      filters: [['lastmodified', 'onorafter',
                 'yesterday']],   // or use a stored last-run timestamp
      columns: [/* all custrecord_ fields */]
    });
    var batch = [];
    s.run().each(function(result) {
      batch.push(mapResultToPayload(result));
      if (batch.length >= 50) { flushBatch(batch); batch = []; }
      return true;
    });
    if (batch.length) flushBatch(batch);
  }
  return { execute: execute };
});

Option C — PostgreSQL → NetSuite (write-back)

For calculated fields (Current 6MRA, Current Tier, Last Tier Evaluated), PostgreSQL pushes results back to NetSuite after each monthly calculation run, using the NetSuite REST API:

# Python — write 6MRA + tier back to NS custom record after monthly calc

import requests, json

def write_tier_to_netsuite(ns_record_id: int, tier: str, sixmra: float, eval_date: str):
    url = (f"https://<account>.suitetalk.api.netsuite.com"
           f"/services/rest/record/v1"
           f"/customrecord_hyp_partner_params/{ns_record_id}")
    payload = {
        "custrecord_hyp_b_cur_tier":        tier,
        "custrecord_hyp_b_6mra":            sixmra,
        "custrecord_hyp_b_tier_last_eval":   eval_date
    }
    resp = requests.patch(url,
        json=payload,
        auth=OAuth1(consumer_key, consumer_secret, token, token_secret),
        headers={"Content-Type": "application/json"})
    resp.raise_for_status()

Section 5

Implementation Plan

Recommended sequence across four phases. Phases 1–2 can be run in parallel after alignment; Phase 3 requires Phase 1 custom records to exist in NetSuite; Phase 4 requires Phase 3 endpoints to be live.

Phase 1 — NetSuite Configuration

  1. Create Custom Record Type: Partner Agreement Parameters
    In NetSuite: Setup → Customization → Record Types → New. Name: "Partner Agreement Parameters"; Internal ID: customrecord_hyp_partner_params. Add a parent relationship field (custrecord_hyp_partner) linking to the Partner/Vendor record. Set "Show in List" and "Allow Quick Add" as appropriate. Enable versioning via a sync_version integer field.
  2. Add all custom fields per the specification in Section 2
    Create each field listed in the Master Partner Parameters spec above. Group them by exhibit section using field groups. Use List/Record type for all enumerated fields to enforce valid values. For Exhibit D.1 fields, set a display condition: show only when Agreement Template Version = v6 or Exhibit D.1 Active = true.
  3. Build the "Master Partner Parameters" subtab on the Partner form
    Navigate to Customization → Forms → Partner Form → Subtabs. Add a new subtab labeled "Master Partner Parameters." Use a Custom Sublist to display all customrecord_hyp_partner_params records linked to the current partner. This allows viewing all agreement versions in one place.
  4. Create validation SuiteScript (UserEvent BeforeSubmit)
    Write a BeforeSubmit script to: (a) enforce that Exhibit A is always active if Exhibit B is active; (b) require VAST Track Commission Amount when Exhibit D.1 is activated; (c) auto-set Post-Term Residual Continues based on Termination Type; (d) calculate Tier Eligibility Start Date as Effective Date + 6 months. Deploy to the custom record type.
  5. Deploy UserEvent AfterSubmit sync script
    Deploy the SuiteScript push-on-save shown in Section 4. Store the sync API token in a Script Parameter (Setup → Script → Deployment → Parameters). Set governance usage to ≤100 units. Test with a sandbox partner record first.
  6. Create Saved Search for nightly delta export
    Create a saved search on the custom record type filtering Last Modified on or after {yesterday} with all compensation fields as columns. This saved search is used by both the nightly Scheduled Script and as an ODBC data source for reporting.

Phase 2 — PostgreSQL Setup

  1. Deploy the schema from Section 3
    Run the DDL script in your PostgreSQL instance (14+ recommended for gen_random_uuid() default). Enable pg_audit extension for row-level auditing, or use the parameter_audit_log table with triggers. Create a dedicated database user hyp_comp_api with INSERT/UPDATE/SELECT on the three tables and no DDL access.
  2. Build the Sync API microservice
    Deploy a lightweight Node.js (Express) or Python (FastAPI) service with two endpoints: POST /api/partner-params/upsert (single record) and POST /api/partner-params/batch (up to 50 records). Implement HMAC-SHA256 request verification using a shared secret stored in NetSuite Script Parameters and in the microservice's environment variables.
  3. Implement audit diff logging
    In the upsert endpoint, before executing the INSERT … ON CONFLICT, SELECT the current row and compute field-level diffs. Insert one row per changed field into parameter_audit_log in the same transaction. This provides a complete amendment history aligned with Exhibit G (Change Requests).
  4. Write the 6MRA calculation function
    Create a PostgreSQL function calculate_6mra(partner_id UUID, as_of_date DATE) that queries the last 6 months of ESCR from compensation_calculations, computes the average, determines the applicable tier, and updates b_current_tier, b_current_6mra, and b_tier_last_evaluated in partner_agreement_params. Schedule this as a monthly pg_cron job or call it from the nightly batch.

Phase 3 — Initial Data Load

  1. Map existing partner agreements to the new field structure
    For each active partner, review the executed agreement to identify: which template version was used (v1 or v6), which exhibits are active, and the agreed rates. Particularly check Exhibit B for tiered vs flat structure and Exhibit E/F for any filled-in eligible product lists. Document any partners with custom rates.
  2. Bulk-load existing partners via NetSuite CSV Import
    Use NetSuite's CSV Import → Custom Records to load all partners' agreement parameters. The import maps spreadsheet columns to custrecord_hyp_ field IDs. Validate that each record triggers the AfterSubmit sync script (check Sync API logs) or run the nightly batch manually after import.
  3. Backfill historical ESCR data into compensation_calculations
    For tiered partners, backfill historical monthly ESCR from your existing system into PostgreSQL. This allows the 6MRA function to calculate accurate current tiers at go-live rather than resetting all partners to SELECT tier.

Phase 4 — Ongoing Operations

  1. Run monthly compensation calculation
    Call calculate_6mra() for all tiered partners at the start of each commission period. Then run the compensation calculation job, which reads partner_agreement_params, applies the applicable rate (tier or flat), applies the withholding check (300% rule), and writes results to compensation_calculations.
  2. Push tier updates back to NetSuite
    After each monthly 6MRA calculation, use the NetSuite REST API PATCH call (Python example in Section 4) to update custrecord_hyp_b_cur_tier, custrecord_hyp_b_6mra, and custrecord_hyp_b_tier_eval_dt on the partner's NS record. This ensures the NS form always shows current tier for the Channel team's reference.
  3. Monitor sync health
    Build a reconciliation query: compare COUNT(*) of NS custom records (via ODBC or Scheduled Script export) against PostgreSQL rows by ns_record_id. Alert if any NS record has ns_last_modified > pg_synced_at + 5 minutes — that record missed the real-time push and will need the nightly batch to catch it. Log to a sync_health table and expose a dashboard.
  4. Process Exhibit G change requests
    When a partner signs a Change Order (Exhibit G), update the relevant fields on the NS custom record. The AfterSubmit script auto-pushes the delta to PostgreSQL. The audit log captures the old and new values with a reference to the Change Order number (store in exception_notes or a dedicated change_order_ref field). Future amendments automatically version via sync_version increment.

Key risk: Exhibit E/F blanks

Many existing agreements have blank eligible/ineligible product fields in Exhibits E and F. Before enabling compensation calculations for those exhibits, ensure the Channel team has completed these fields for all active partners. Consider a NetSuite validation rule that prevents Exhibit E/F from being marked Active unless the eligible products field is populated.

VAST Track (Exhibit D.1) migration note

Partners currently on v1 agreements do not have Exhibit D.1. When re-papering or amending to v6, Exhibit D.1 will need to be evaluated. The VAST Track Commission Amount ($) is a negotiated blank in the template — ensure this is captured before setting Exhibit D.1 Active = true, or the calculation engine will produce zero compensation for VAST Track transactions.