Blog

How to create custom-coded quote modules for Revenue Hub using Codex

Written by Jonathan Price | Sep 8, 2026, 10:57:23 AM

A practical, field-tested workflow for scoping, prompting, building, uploading and testing HubSpot custom quote modules with ChatGPT, Codex and the HubSpot CLI.

HubSpot's standard quote modules are enough for many businesses. But quoting becomes harder when buyers need to see products and services grouped in a particular way, different terms must appear under different conditions, or the quote needs to reflect a commercial model that does not fit a standard line item table.

That is where custom-coded quote modules become useful.

HubSpot now supports custom React-based modules that can sit alongside its standard quote modules. You can change a specific part of the quote experience without rebuilding the entire quote as a legacy custom template. The underlying quote, deal and line item data can remain in HubSpot, while the custom module controls how selected information is presented. HubSpot's overview includes examples such as grouped line items, optional items, billing schedules, conditional terms, navigation, bespoke styling and mandatory buyer acknowledgements.

We recently used this approach on a real Growth London client delivery. The client needed a clearer way to present different categories of line items to buyers. We built a module that grouped line items using a Product Type property, hid empty sections, added section subtotals, displayed a discount column only when discounts existed, supported different language labels and preserved HubSpot's native line item editing.

The code mattered, but it was not the hardest or most important part of the job.

The first mistake is to think of this as a coding project. It is really a requirements translation project. You are translating the way a business sells into a quote module that HubSpot can render, sales users can manage and buyers can understand.

The biggest unlock is not simply that Codex can write a React module. It is that a consultant can now move from client call notes to an approved quote-module brief and then to a working HubSpot module in one controlled workflow.

What custom quote modules can be used for

Before looking at the build process, it helps to understand the range of problems a custom module can solve.

Custom line item presentation

A custom module can:

  • group line items into product, service, implementation, support or recurring-fee sections;
  • separate optional add-ons from committed items;
  • hide irrelevant columns;
  • add subtotals by section;
  • show a discount column only when a genuine discount exists;
  • create custom totals or buyer-facing summaries;
  • display one-off and recurring charges separately; and
  • show dynamic sections based on the line items included in the quote.

Conditional quote content

Modules can also display content according to quote, buyer or product data. For example:

  • product-specific terms and conditions;
  • regional clauses based on buyer country;
  • implementation notes for selected services;
  • data-processing language for particular products;
  • conditional buyer acknowledgements; or
  • different content for new business, renewal and expansion quotes.

Billing and commercial summaries

Other useful applications include:

  • billing schedules;
  • renewal summaries;
  • multi-year price ramps;
  • annual versus monthly breakdowns;
  • product-family summaries; and
  • explanatory calculations that help the buyer understand the proposal.

Regional and multilingual templates

The same module can support:

  • alternative label sets;
  • regional terminology;
  • multiple languages;
  • localised headings and explanatory copy; and
  • conditional content for different markets.

Richer proposal content

A HubSpot quote is a web-based sales document, not just a PDF. Custom modules can add richer proposal elements such as:

  • branded section dividers;
  • product or service explanations;
  • navigation for longer quotes;
  • case studies or testimonials selected by sector;
  • implementation plans; and
  • interactive acknowledgements before acceptance.

There is an important boundary here. A custom module should usually improve the quote experience. It should not quietly become a shadow CPQ or pricing engine unless that has been deliberately designed, scoped and governed.

The workflow at a glance

Our repeatable process is:

  1. Capture the client brief and identify where standard HubSpot quote modules are not enough.
  2. Use a dedicated ChatGPT client thread to analyse call notes, screenshots, emails and existing quote examples.
  3. Produce a Custom Quote Module Brief and get it approved by the client.
  4. Convert the approved brief into a build-ready specification.
  5. Set up the local project, HubSpot's quote-dev-starter, Codex and HubSpot CLI authentication.
  6. Use the main client ChatGPT thread to write tightly scoped Codex prompts.
  7. Use Codex as the builder inside the project repository.
  8. Upload the project to the correct HubSpot account using the CLI.
  9. Add the module to a cloned quote template and test it with representative quotes.
  10. Iterate against the editor, preview, published quote and PDF output, then capture the learning for the next project.

The division of labour is simple:

Environment Primary role
ChatGPT client thread Client context, requirements analysis, scoping, prompt design and QA decisions
Codex project Repository inspection, code changes, local checks and CLI commands
HubSpot Quote data, template configuration, project builds and real-output testing

Step 1: capture the commercial requirement

Start with the quote problem, not the technical solution.

Useful source material may include:

  • discovery call notes or transcripts;
  • screenshots of current quotes;
  • examples produced in other systems;
  • emails explaining what sales users find difficult;
  • the client's Product Library structure;
  • relevant line item and quote properties;
  • regional or language variations; and
  • examples of the finished output the buyer should receive.

At this stage, separate four things that are often blurred together:

  1. Data requirements: what properties and objects hold the source information?
  2. Display requirements: what should the buyer see and in what order?
  3. Commercial logic: what controls price, discounts, totals or billing?
  4. Operational requirements: what must a sales user maintain when creating the quote?

That distinction prevents a display module from accidentally taking responsibility for pricing or automation.

Example prompt: analyse call notes and produce the client brief

We are scoping a custom-coded HubSpot quote module for a client.

Review the call notes, screenshots, current quote examples and email requirements in this thread. Produce a client-facing Custom Quote Module Brief.

Include:

1. Background and desired buyer experience
2. Current quote-template limitations
3. Required custom modules
4. Required quote, line item, product or associated-object properties
5. Required display logic
6. Conditional behaviour
7. User-editable module fields
8. Language or regional requirements
9. What remains native HubSpot functionality
10. Explicit out-of-scope items
11. Acceptance criteria
12. Questions to confirm with the client

Important:
- Do not invent requirements that are not supported by the source material.
- Do not assume the module should change quote totals unless this is explicitly required.
- Separate display requirements from pricing, automation and data requirements.
- State what sales users will continue to manage through native HubSpot quote line items.
- Flag any unknown property names or unclear calculation rules for confirmation.

Write this as a concise consulting brief that can be shared with the client for approval.

Step 2: get the Custom Quote Module Brief approved

The approved brief is the control point between discovery and development.

It should answer questions such as:

  • What module or modules are being built?
  • What business problem does each module solve?
  • Which properties are the source of truth?
  • Which behaviour is conditional?
  • Which labels or settings can a HubSpot user edit?
  • Does the module only display values, or does it also affect acceptance or payment behaviour?
  • What will remain part of HubSpot's native quote process?
  • What does a successful test look like?
  • What is explicitly not included?

Client approval is valuable even on a small build. It stops design preferences and new commercial logic being introduced halfway through development as if they were corrections.

Example prompt: turn the approved brief into a Codex build specification

The client has approved the Custom Quote Module Brief above and supplied the clarifications below.

[Insert the final clarifications.]

Convert the approved brief into a build-ready technical specification for Codex.

Include:
- module name and purpose;
- user-editable fields in the module editor;
- exact quote, line item, product or associated-object properties required;
- display rules;
- grouping and sorting rules;
- calculation rules, including rounding and currency treatment;
- conditional behaviour;
- fallback behaviour for missing or unexpected data;
- editor and quote-blueprint behaviour;
- temporary debug behaviour;
- test scenarios;
- accessibility and print/PDF considerations;
- non-goals; and
- deployment assumptions.

Where an internal HubSpot property name has not been confirmed, mark it as an unresolved dependency. Do not invent one.

Keep the specification implementation-focused but readable by a HubSpot consultant.

Step 3: set up the project plumbing

For this kind of work, the plumbing is a meaningful part of the delivery. Codex needs a correctly structured local project, the HubSpot CLI needs to be authenticated to the right account, and the project needs to reach the client's portal safely.

At the time of writing, HubSpot requires Revenue Hub Professional or Enterprise for custom quote modules. Its build guide also says that quote-module projects cannot currently be created through the normal CLI project-creation flow. Instead, start with HubSpot's official quote-dev-starter project.

Basic setup sequence

  1. Create a dedicated local project folder for the client.
  2. Download or clone quote-dev-starter into that folder.
  3. Open the project folder in Codex.
  4. Install its dependencies.
  5. Authenticate the relevant HubSpot account.
  6. Link the project directory to the appropriate account.
  7. Confirm the project structure and target account.
  8. Run the first upload and create the developer project when prompted.

Typical commands are:

npm install
hs account auth
hs account list
hs account link

You can also set a default account explicitly:

hs account use <account-name-or-id>

HubSpot's current account command documentation recommends hs account link when different project directories target different accounts. The link is stored in the project's local .hs/settings.json file. This is particularly useful for a consultancy working across multiple client portals because it reduces the chance of running a command against the wrong account.

Even with a linked or default account, we prefer to make the target explicit when uploading:

hs project upload --account=<account-id-or-name> --debug

The first upload is different from later uploads. HubSpot will ask you to name and create the project, then build and normally auto-deploy it. HubSpot's project command documentation confirms that hs project upload creates a build and prompts to create the project if it does not yet exist.

Interactive prompts can trip up an otherwise automated Codex workflow. On the first upload, either complete the prompt yourself or tell Codex to stop and report any request for confirmation. Do not let an agent retry the same failed upload repeatedly without checking whether the project exists and whether human confirmation is required.

Example Codex prompt: check project setup

Inspect this HubSpot quote-dev-starter project and confirm whether it is ready for custom quote module development.

Do not build or change a module yet.

Use safe read-only checks to inspect:
- package installation state;
- project structure;
- hsproject.json;
- the relevant package.json files and available scripts;
- HubSpot CLI availability and version;
- authenticated HubSpot accounts;
- the account linked to this directory, if any;
- the current or default HubSpot account;
- whether this project already exists in the target HubSpot account; and
- whether the first upload is likely to trigger an interactive project-creation prompt.

Do not expose or print access keys, tokens or other secrets.

After checking, report:
1. The target account you believe this directory is connected to.
2. Any missing or ambiguous setup.
3. The exact validation and upload commands you recommend.
4. Any step that needs human confirmation before you continue.
5. Any assumptions that must be resolved before development begins.

Step 4: use ChatGPT as the strategy partner and Codex as the builder

The effective workflow was not to ask Codex to infer the whole solution from a sentence or two.

We kept the client delivery context in a dedicated ChatGPT thread. That thread held the call notes, screenshots, decisions, approved brief and client feedback. We then used it to write a focused prompt for Codex.

Codex worked inside the project repository. It could inspect the starter project, edit the relevant files, run TypeScript and formatting checks, review the diff and use the HubSpot CLI.

In practice, the loop looked like this:

  1. Ask the main ChatGPT thread to write the next Codex prompt.
  2. Give that prompt to Codex inside the project.
  3. Let Codex inspect, build, check and report.
  4. Bring Codex's summary and any HubSpot output back to the main thread.
  5. Decide the next build or QA step using the approved client context.
  6. Repeat until the module passes real quote tests.

This separation gives each environment a clear job. ChatGPT owns context and judgement. Codex owns the repository and execution. HubSpot remains the source system and test environment.

It also makes the process easier to audit. The approved brief explains what should be built, the Codex prompt explains the requested change, and the repository diff shows what actually changed.

Step 5: build the smallest useful module first

Do not ask Codex to build the entire quote experience in one prompt.

Start with one module that has a clear source of truth and a testable output. Build it, upload it and test it before adding a dependent summary, conditional terms block or interactive acknowledgement.

In our anonymised client example, the first module was a grouped line item table.

The standard table was accurate but commercially flat. Buyers needed to understand which items belonged to different parts of the offer. The custom module:

  • grouped line items according to an existing Product Type property;
  • hid groups that contained no line items;
  • displayed a subtotal for each section;
  • showed SKU, product name, quantity, unit price and net price;
  • displayed the discount column only when at least one real discount existed;
  • supported alternative language labels; and
  • kept HubSpot's native line item editing intact.

That final point matters. If a custom module replaces the visible line item table, HubSpot says the standard Line items module must be hidden rather than removed. The standard module remains the mechanism through which users add, edit and remove the underlying line items. The custom module displays the data. It does not replace the native editing process.

Example Codex prompt: build the first module

Build Module 1 only: Grouped Line Items.

First inspect the quote-dev-starter patterns and the approved technical specification in this repository. If the brief conflicts with the current HubSpot starter or an exact property name is unresolved, stop and report the conflict rather than inventing an implementation.

Purpose:
Create a display-only HubSpot quote module that presents quote line items in sections based on the client's Product Type property.

Do not:
- create, edit or remove HubSpot line items;
- change quote totals or deal amounts;
- introduce a second module;
- hard-code prices;
- remove the requirement for HubSpot's native Line items module; or
- pass the full quoteTemplateContext or one of its full sub-objects into client-side props.

Implementation requirements:
- Follow the current quote-dev-starter custom quote module pattern.
- Export Component, fields, meta and hublDataTemplate as required by the starter.
- Support both QUOTE and QUOTE_BLUEPRINT content types.
- Use hublDataTemplate to extract only the fields required by this module.
- Reuse existing types and project conventions where possible.
- Provide sensible blueprint/editor fallback data.
- Keep presentation accessible and suitable for print/PDF.

Required line item data:
- SKU;
- product name;
- quantity;
- unit price;
- discount value or percentage, according to the approved brief;
- net line value;
- Product Type internal value; and
- quote currency.

Display rules:
- Group line items by the confirmed Product Type internal value.
- Use the approved group order and labels.
- Hide empty groups.
- Display a configurable heading above the module.
- Show SKU, product, quantity, unit price and net price.
- Show a subtotal for each group.
- Show the discount column only when at least one line item has a genuine discount.
- Show any total-discount summary only when a genuine discount exists.
- Use consistent column widths across every group.
- Allow product names to wrap naturally.
- Right-align numeric columns.
- Handle missing or unexpected Product Type values defensively.

Configuration fields:
- show or hide module heading;
- heading label;
- approved language or label set;
- editable display label for each group; and
- temporary debug-unmapped-items toggle.

Debug behaviour:
When enabled, show unmapped line items and the Product Type value detected for each one. Make the debug output visually distinct and easy to disable before go-live.

Test scenarios:
- quote template or blueprint view;
- draft quote preview;
- published quote;
- print/PDF output;
- no-discount quote;
- discounted quote;
- one populated group;
- multiple populated groups;
- missing Product Type;
- zero quantity or zero-value edge cases, if HubSpot permits them; and
- alternative language labels where internal Product Type values remain stable.

Before editing, summarise your intended file changes.

After implementation:
1. Summarise files created or changed.
2. List every assumed HubSpot property name.
3. Run the repository's existing type, lint, test and formatting scripts where available.
4. Run git diff --check.
5. Show a concise diff summary.
6. Do not upload until the local checks pass.
7. If local checks pass, report that the project is ready for upload and provide the exact command.

Notice what this prompt does not do. It does not tell Codex to invent field names, rewrite unrelated parts of the starter or build several modules at once. It defines the module boundary, data boundary, safety constraints and test scenarios.

HubSpot's starter uses hublDataTemplate to prepare specific server-side data for the React component. This is also a security boundary. HubSpot warns that passing the full quoteTemplateContext, or a full sub-object such as the quote, into an island exposes all of those properties in the published page source. Extract only the values the module genuinely needs.

Step 6: upload the module using HubSpot CLI

Once the local checks pass, upload the project to the named account.

hs project upload --account=<account-id-or-name> --debug

Using the account flag is a useful last line of defence when you work with more than one client account. The account link, current directory and explicit upload target should all agree.

Example Codex prompt: upload safely

Prepare and upload the current HubSpot quote module project to the intended client account.

Before uploading:
1. Confirm the current directory contains hsproject.json.
2. Run hs account list.
3. Confirm the directory-linked account, if present.
4. Confirm the intended account ID/name matches the approved deployment target.
5. Run the repository's available type, lint, test and formatting checks.
6. Run git diff --check.
7. Stop if the account target is ambiguous or any local check fails.

Then run:
hs project upload --account=<account-id-or-name> --debug

Important:
- Do not print authentication secrets.
- If HubSpot asks to name or create the project, stop and report the exact prompt so a human can confirm it.
- Do not retry a failed upload until you have diagnosed the failure.
- Do not use force flags to bypass warnings.

After upload, report:
- whether the upload succeeded;
- the project and build identifier shown by HubSpot;
- whether the build deployed automatically;
- any warnings or errors;
- the project activity URL, if the CLI returned one; and
- the next manual step in HubSpot.

The first successful upload is a useful milestone. Once the project exists and its build has deployed, later uploads are normally more straightforward.

Step 7: clone a quote template and test safely

Do not add an untested module to the live template used by the sales team.

Instead:

  1. Clone the relevant quote template.
  2. Give the clone an obvious development or QA name.
  3. Add the custom module to the cloned template.
  4. Keep the native Line items module present. Hide it if the custom module replaces its visible presentation.
  5. Create a test deal or use a clearly identified test record.
  6. Add representative line items, including the awkward cases.
  7. Create a draft quote from the cloned template.
  8. Test the editor, preview, published view and PDF or print output.
  9. Record defects against the approved acceptance criteria.
  10. Only promote the module to a production template after client approval.

Example prompt: create the QA checklist

Create a practical QA checklist for the approved Grouped Line Items custom quote module.

Use the approved brief, technical specification and acceptance criteria in this thread.

Organise the checklist into:
1. Project build and deployment checks
2. Cloned quote-template checks
3. Native Line items module checks
4. Draft quote and editor checks
5. Preview checks
6. Published quote checks
7. Print/PDF checks
8. Data and calculation checks
9. Language and regional checks
10. Client acceptance checks

Include scenarios for:
- no discounts;
- one discounted item;
- several discounted items;
- one Product Type group;
- several Product Type groups;
- an empty group;
- a missing or unexpected Product Type value;
- long product names and SKUs;
- different quantities and currencies where supported;
- alternative language labels;
- the hidden but retained native Line items module; and
- disabling all debug output before go-live.

For each test, provide:
- setup/data required;
- expected result;
- where to test it: editor, preview, published quote or PDF;
- pass/fail field; and
- notes/evidence field.

Do not invent expected calculations. Use only the rules in the approved specification and flag any gap.

Real published output matters. A table that looks right in the template editor may wrap differently in a browser or PDF. Interactive behaviour may need a static print treatment. Long labels can move columns. A zero discount can still create an unwanted empty column if the condition is too loose.

There is another important deployment detail: HubSpot says quotes are rendered when they are published. A newly deployed module version affects future quotes and unpublished drafts, but not quotes that have already been published. That is useful for stability, but it means you must publish a new test quote when validating a new build rather than relying on an older published URL.

Step 8: iterate from real quote output

Our first module worked functionally, but real quote testing exposed the details that made it client-ready:

  • padding needed adjustment;
  • the module needed a clearer heading;
  • columns needed consistent widths across sections;
  • long SKUs and product names needed sensible wrapping;
  • the discount column needed to disappear when all discounts were zero; and
  • labels needed to work in another language.

That is the right order of work:

  1. Make the data and logic correct.
  2. Make the output usable.
  3. Make it visually coherent with the wider template.
  4. Test every publishing format.
  5. Ask the client to review a realistic quote, not an abstract component.

Keep each iteration narrow. A presentation refinement should not quietly rewrite calculation or grouping logic.

Example Codex prompt: presentation refinement

The Grouped Line Items module is functionally correct and has passed its data tests. Make a presentation-only refinement to this module.

Observed issues from the latest test quote:
- grouped tables use inconsistent column widths;
- the module needs a clearer heading;
- long product names need more natural wrapping; and
- numeric values should align consistently.

Requirements:
- add or refine the configurable module heading;
- use consistent column widths across every populated group;
- right-align quantity and monetary columns;
- let product names wrap naturally without breaking the table;
- make long SKUs wrap or truncate according to the approved design;
- preserve current grouping, ordering and subtotal logic;
- preserve discount visibility logic;
- preserve Product Type mapping;
- preserve language-label behaviour;
- preserve print/PDF support; and
- do not add another module or change any commercial calculation.

Before changing code, identify the files and styles you expect to touch.

After the change:
1. Summarise files changed.
2. Explain why the changes cannot alter calculations.
3. Run the existing local checks and git diff --check.
4. Provide a concise diff summary.
5. If all checks pass, upload to the explicit client account.
6. Report the new build/deployment result and the exact visual scenarios to retest.

Step 9: add further modules only after the first is stable

Once the first module has a reliable data extraction pattern, tested layout and repeatable deployment process, you can add more complex modules.

Examples might include:

  • a billing schedule derived from line items;
  • conditional terms based on the products selected;
  • an annual or renewal summary;
  • optional add-ons;
  • a buyer acknowledgement that controls acceptance;
  • a regional content block; or
  • a richer proposal section driven by quote data.

The key principle is to preserve the source of truth.

If a value affects what the client is charging, it should normally come from the Product Library and actual quote line items, or from another deliberately governed commercial system. Avoid hard-coding prices into a presentation module simply because it is technically possible.

For summary modules, a sensible priority order is often:

  1. use an explicit manual override where the approved requirement permits one;
  2. otherwise use the relevant quote line item's actual value;
  3. otherwise use a clearly defined configuration fallback; and
  4. otherwise hide the row or show a safe empty state.

The correct order depends on the client's approved rules. The important point is to define it before Codex builds it.

Step 10: capture the reusable process

The final deliverable should not just be working code.

Capture:

  • the approved Custom Quote Module Brief;
  • the final technical specification;
  • confirmed property names and expected values;
  • repository and project location;
  • target HubSpot account and project name;
  • the prompts that produced reliable results;
  • build and deployment steps;
  • QA checklist and evidence;
  • module-editor guidance for administrators;
  • Product Library maintenance responsibilities;
  • known limitations and edge cases; and
  • a short change process for future updates.

This turns a successful one-off delivery into a repeatable consulting method.

It also makes future work safer. A later developer or consultant can see why the module exists, which data it expects, what it must not change and how to test it before deployment.

Lessons from the field

Do not start with code

Call notes and screenshots are not a build specification. Translate them into an approved brief first.

Do not ask Codex to build everything at once

One module, one purpose and one acceptance test creates a much more reliable loop.

Keep the native Line items module

When a custom module replaces the visible line item table, hide the standard HubSpot module rather than removing it. Native editing still depends on it.

Extract only the data you need

Do not pass the full quote context into a client-side island. Apart from making the implementation harder to reason about, it can expose unnecessary quote and associated-record properties in the published source.

Do not hard-code commercial values unnecessarily

Let governed Product Library and quote line item data own pricing wherever possible.

Make the target account unambiguous

Link the client project directory to the correct HubSpot account, check the account before upload and use an explicit --account target.

Treat the first upload as a controlled step

The first upload may require an interactive project creation confirmation. Handle that deliberately rather than allowing repeated blind retries.

Test a cloned template with realistic data

Use real combinations of line items, including discounts, missing classifications, long labels and regional variations.

Test every output

Review the quote editor, preview, newly published quote and print/PDF output. They are related, but they are not identical rendering contexts.

Keep ChatGPT and Codex in connected but distinct roles

ChatGPT is most useful as the client-context and prompt-strategy partner. Codex is most useful as the repository-aware builder. The workflow becomes stronger when each has a clear responsibility.

Final thoughts

Custom-coded quote modules are not just a developer feature. They are a way to make Revenue Hub reflect how a business actually sells without abandoning HubSpot's native quote and line item model.

AI coding tools have lowered the barrier to building them, but they have not removed the need for consulting judgement. The quality of the outcome still depends on a clear brief, governed data, a tightly scoped build, safe deployment and testing against real buyer-facing output.

Used well, this workflow lets you keep HubSpot as the commercial source of truth while giving buyers a quote experience that matches the way the business sells.

Official resources

Technical note: HubSpot's custom quote module and developer tooling documentation is evolving. Check the current prerequisites, starter project and CLI guidance before beginning a client build.