# Brief developer AI pricing calculator in one hour

> Get a step‑by‑step plan to brief a developer for an AI‑ready pricing calculator page in one hour.

Source: https://comppound.com/blog/brief-developer-ai-pricing-calculator-in-one-hour (published 2026-10-21)

What you need: a one‑page brief that a developer can turn into a live pricing calculator in a single sprint.
The brief must contain the data model, the prompt structure, the UI skeleton, validation rules, and the integration points so the developer can focus on coding instead of clarifying assumptions.

## Define the goal and the user
Start the brief by stating the purpose: let customers see an instant quote for your SaaS based on their usage and contract length.
Describe the target audience: small‑to‑medium businesses that want a quick estimate before contacting sales.
Mention the key outcome: a page that accepts three inputs (users, seats, months) and returns a total price with optional add‑ons.

## Map the data schema
List the exact data that the calculator must handle.
```markdown
- base_price_per_user (number)
- discount_rate (percent)
- add_on_services (array of {name, price_per_month})
- currency (string)
- tax_rate (percent)
```
These fields should live in a JSON file or a database table that the backend can read.
Make sure the schema is versioned so future changes don’t break the UI.

## Draft the prompt logic
Give the developer a concrete prompt template for the LLM that will calculate the price.
```text
“Calculate the total price for a SaaS subscription: {users} users, {months} months, add‑ons: {add_ons}. Use the base price ${base_price_per_user} per user, apply {discount_rate}% discount, add tax {tax_rate}%, and output the final amount in {currency}.”
```
Specify that the prompt must return a JSON object with `subtotal`, `discount`, `tax`, and `total`.
Include an example call and expected JSON response so the developer knows what to test against.

## Build the UI wireframe

![Sketch of a simple pricing calculator form with fields for users, months, and add‑ons.](https://images.unsplash.com/photo-1711606815631-38d32cdaec3e?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wxMDMwMjQ2fDB8MXxzZWFyY2h8MXx8YnJpZWYlMjBkZXZlbG9wZXIlMjBhaSUyMHByaWNpbmclMjBjYWxjdWxhdG9yfGVufDB8MHx8fDE3OTI1NjkxNTh8MA&ixlib=rb-4.1.0&q=80&w=1080)
*Photo by [Jakub Żerdzicki](https://unsplash.com/@jakubzerdzicki?utm_source=comppound&utm_medium=referral) on [Unsplash](https://unsplash.com/?utm_source=comppound&utm_medium=referral)*

Sketch a minimal form with three fields: Users, Months, Add‑ons (checkboxes).
Add a “Get Quote” button that triggers the LLM call and displays the result below the form.
The brief should note the need for responsive styling and clear error messages if required fields are missing.

## Specify validation & fallback
Provide a list of validation rules the frontend must enforce before sending the prompt.
```markdown
- Users must be an integer ≥ 1
- Months must be an integer between 1 and 24
- Selected add‑ons must exist in the add_on_services array
- Show a quote only after the total cost reaches a reasonable minimum
```
If any rule fails, the UI should show a user‑friendly error and stop the request.
Mention that the backend should double‑check these rules to guard against tampering.

## Outline integration points
Describe where the calculator sits in the stack.
* Frontend: React component that calls the `/api/price-calc` endpoint.
* Backend: Node/Express route that loads the schema, renders the prompt, calls the LLM, and returns the JSON.
* Database: Read‑only table with pricing parameters.
* Monitoring: Log each calculation request with timestamp and input payload for audit purposes.

## Test & handoff checklist
Provide a two‑column table of actions the QA engineer should perform and the developer’s deliverables.
Make sure the developer marks the page as “ready” only after all tests pass and documentation is complete.

## Common mistakes
1. **Hard‑coding values** – keep all numbers in the schema to allow quick updates.
2. **Missing error handling** – a silent failure is worse than a clear message.
3. **Assuming the LLM will format JSON correctly** – always parse the response and guard against malformed data.

With this brief, a developer can build the calculator, test it, and ship it in one sprint.

Want us to look at your page? [Book a call](/contact) and we’ll map out the biggest growth opportunities.

### Define the goal and the user – deeper detail

**User story**
*As a small‑to‑medium business owner, I want to type in the number of users, the length of the contract, and any optional services so I can see an instant, itemised quote before I talk to a sales rep.*

**Success criteria**
- The page loads in under two seconds on a typical broadband connection.
- After hitting **Get Quote**, the result appears within one second of the LLM response.
- All three inputs are visible on the screen without scrolling on a mobile device.

**Why it matters**
If the quote is hidden behind a form that requires an email address, many prospects drop off before ever seeing a price. A pure‑calculation page removes that friction and gives the product manager a concrete metric to track (e.g., number of quote requests per week).

### Map the data schema – practical considerations

The JSON schema should be stored in a version‑controlled repository (e.g., a `pricing-schema.json` file in the same repo as the front‑end code). Here is a more explicit example:

```json
{
  "base_price_per_user": 25,
  "discount_tiers": [
    { "min_users": 1,   "rate": 0 },
    { "min_users": 20,  "rate": 5 },
    { "min_users": 50,  "rate": 10 }
  ],
  "add_on_services": [
    { "name": "Premium Support", "price_per_month": 5 },
    { "name": "Analytics Pack",   "price_per_month": 8 }
  ],
  "currency": "USD",
  "tax_rate": 7.5
}
```

**Versioning tip** – tag each change with a semantic version like `v1.2.0`. The front‑end can fetch the schema at build time, while the back‑end can read the latest version at runtime. This prevents a situation where the UI expects a field that the back‑end no longer provides.

**Extending the model** – if you later add a “contract length discount,” add a field such as `contract_discount` that is an array of `{months, rate}` objects. Because the schema lives in a single source of truth, the UI can automatically render a new dropdown without code changes.

### Draft the prompt logic – building a reliable LLM call

When the front‑end sends the request, build the prompt string programmatically rather than hard‑coding it. In pseudo‑code:

```js
const prompt = `
Calculate the total price for a SaaS subscription:
- Users: ${inputs.users}
- Months: ${inputs.months}
- Add‑ons: ${inputs.addOns.join(', ') || 'none'}

Use the base price ${schema.base_price_per_user} per user.
Apply any discount tier that matches the user count.
Add the price of each selected add‑on.
Apply tax ${schema.tax_rate}%.
Return the result as JSON with keys: subtotal, discount, tax, total.
`.trim();
```

**Expected JSON response** – define the exact shape:

```json
{
  "subtotal": 1500,
  "discount": 150,
  "tax": 108,
  "total": 1458
}
```

If the LLM returns malformed JSON (e.g., missing a closing brace), the back‑end should fall back to a safe error object:

```json
{ "error": "Invalid response from price engine" }
```

**Why explicit JSON matters** – parsing a free‑form text response is brittle. By forcing a strict format, you eliminate the need for regex hacks and reduce the chance of a broken UI after a model update.

### Build the UI wireframe – accessibility and usability

**Field types**
- **Users** – `` so browsers enforce the integer rule.
- **Months** – `` with options 1‑24; this prevents users from typing out‑of‑range values.
- **Add‑ons** – a group of `` elements, each labelled with the service name.

**Layout**
Arrange the three inputs in a single column on mobile, and in a two‑column grid on desktop. Use a clear visual hierarchy: label above each field, a generous touch target for the checkboxes, and the **Get Quote** button in a contrasting colour.

**Accessibility**
- Associate every input with a `` element using the `for` attribute.
- Add `aria-live="polite"` to the result container so screen readers announce the quote when it appears.
- Provide a high‑contrast focus outline for keyboard navigation.

**Responsive styling tip** – use CSS flexbox with `flex-wrap: wrap;` and media queries that switch the flex direction at 600 px. This ensures the form stays usable on both tablets and smartphones without a separate mobile‑only stylesheet.

### Specify validation & fallback – front‑end vs back‑end responsibilities

**Front‑end validation** happens instantly, giving users immediate feedback. Implement it in the component’s `onSubmit` handler:

1. Trim whitespace from all inputs.
2. Verify that `users` is an integer ≥ 1.
3. Verify that `months` is an integer ≥ 1 and ≤ 24.
4. Ensure every selected add‑on exists in the schema’s `add_on_services`.

If any check fails, show an inline error message next to the offending field and abort the request.

**Back‑end validation** acts as a safety net. Even if a malicious user bypasses the front‑end, the server should reject the payload with a `400 Bad Request` and a JSON error describing the problem. This double‑layer approach prevents tampering and protects your pricing model from being exploited.

**Fallback behavior** – when the LLM is unavailable (e.g., timeout or rate limit), return a cached static price based on the most recent successful calculation. Indicate the fallback with a subtle note: “Price based on last known rates; contact sales for confirmation.”

### Outline integration points – wiring everything together

**API contract** – define the request and response shapes clearly:

- **Request** (POST `/api/price-calc`)

```json
{
  "users": 12,
  "months": 6,
  "addOns": ["Premium Support"]
}
```

- **Response** (200 OK)

```json
{
  "subtotal": 1800,
  "discount": 90,
  "tax": 127.5,
  "total": 1837.5
}
```

**Error responses** – use standard HTTP status codes (400 for validation errors, 502 for LLM failures). Include a machine‑readable `code` field in the JSON body to aid front‑end error handling.

**CI/CD considerations** – add a unit test that loads the schema, builds a prompt, and asserts that the mocked LLM response matches the expected JSON shape. Include an integration test that runs the full stack in a container and verifies that a sample input yields the correct total.

**Monitoring** – log the following fields for each request:

- Timestamp (ISO 8601)
- Input payload (sanitised, no PII)
- Response time of the LLM call
- Success flag (`true`/`false`)

Set up an alert if the average LLM response time exceeds a threshold (e.g., 800 ms). This keeps the user experience consistent and lets you spot regressions before they affect prospects.

**Security note** – never expose the raw pricing schema to the front‑end. The back‑end should read the schema from a secure location (environment variable, secret manager, or read‑only database) and keep it out of the bundled JavaScript.

### Test & handoff checklist – expanding the quality gate

| QA Action | Developer Deliverable |
| --------- | --------------------- |
| Verify that each input enforces its HTML constraints (type, min, max). | Provide HTML with proper `type`, `min`, `max`, and `required` attributes. |
| Submit a valid payload and confirm the JSON response contains all four numeric fields. | Include a test script that calls `/api/price-calc` with a known good request and asserts the response shape. |
| Submit an invalid payload (e.g., negative users) and check for a 400 error with a helpful message. | Implement server‑side validation that returns `{ "error": "Users must be ≥ 1" }`. |
| Simulate LLM timeout and ensure the fallback price appears with the disclaimer. | Add a mock LLM service that can be toggled to return a timeout; verify the back‑end returns the cached price. |
| Run the page on Chrome, Firefox, and Safari; confirm layout does not break at 320 px width. | Provide CSS using flexbox and media queries that has been tested on the three browsers. |
| Perform an accessibility audit (e.g., using Lighthouse) and aim for a high overall score. | Include ARIA attributes and proper label associations in the markup. |

When all rows are marked “pass,” the developer can label the feature as **Ready for Release**.

### Common mistakes – additional pitfalls and how to spot them

Comppound can help you set up the monitoring and validation layer so the calculator stays reliable as pricing changes. [See how we do it](/services/seo-growth).

## Frequently asked questions

### How do I keep the calculator updated when pricing changes?

Store pricing constants in a versioned database or JSON file and reference them in the prompt. When a new price tier is added, update the schema and redeploy; the LLM will use the latest values automatically.

### Can the calculator handle multiple currencies?

Yes. Include a currency field in the schema and pass it to the prompt. The LLM should output the amount with the appropriate currency symbol, and the UI should display it accordingly.

### What if the LLM returns an error or malformed JSON?

Implement a try/catch around the LLM call. If parsing fails, return a generic “We’re experiencing technical difficulties” message and log the raw response for debugging.
