Generate a price quote document with discount and totals
Three lines, a fixed discount and a 21-day validity become a structured quote with line totals, subtotal, discount and final total, all labelled with your currency code: enter the items, quantities and prices. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Discount
- 250
- Currency
- usd
- Validity days
- 21
- Quote reference
- Q-2026-104
- Customer name
- Northwind Studio
- Document type
- quote
- Currency
- USD
Turn a list of services or products into a consistent, structured quote document without copying figures between a calculator and a template. The generator calculates each line, the subtotal, a fixed discount amount, and the final total, then records how many days the offer remains valid. It also supports a currency code, customer name, and quote reference.
Prepare clear line items for the quote
Start with one record for every service or product the customer is considering. Each record needs a description and a unit price, while quantity defaults to one when it is omitted. Use descriptions that will still make sense after the quote leaves the sales conversation: name the deliverable, package, license, or work phase rather than relying on internal shorthand.
Quantities may represent physical units, subscription seats, consulting days, or any other consistent measure. The generator multiplies each unit price by its quantity and rounds the resulting line total to two decimal places. Prices must be zero or greater, and quantities must be positive.
A zero-priced line is useful for an included deliverable or complimentary service because it documents scope without changing the subtotal. All lines share the currency code supplied for the document. This capability labels monetary values with that code but does not perform currency conversion, add taxes, or infer prices from a catalog.
Supply final commercial figures that are ready to quote. Keeping the input explicit makes the returned document predictable, reviewable, and suitable for downstream automation.
Apply the discount and verify the totals
The optional discount is a fixed amount in the same currency as the line items. If it is omitted, the generator uses zero. It first calculates every line total, adds those rounded values to form the subtotal, rounds the discount to two decimal places, and subtracts it to produce the final total.
This order provides stable results for invoices, approval systems, and document renderers that expect conventional currency precision. The discount cannot be negative and cannot exceed the subtotal. Taxes, deposits, payment schedules, and percentage discounts are intentionally outside this calculation.
Convert a percentage promotion into its approved fixed amount before calling the generator so the arithmetic and the resulting document remain unambiguous.
Use the structured document and validity period
The result is a structured quote rather than a styled PDF. It identifies the document type, currency, validity period in calendar days, normalized line items, and a totals summary. Optional customer and reference fields are included only when supplied, which keeps the output clean for consumers that distinguish missing information from blank information.
The validity period defaults to thirty days and can be set from one through 3,650 days. Because this capability is deterministic and never reads the current clock, it expresses validity as a duration rather than inventing an issue date or expiration date. Your receiving system can combine that duration with the actual issue timestamp when it sends or stores the quote.
If you need a visually finished file, pass this validated structure to your own renderer. The capability performs no network requests, stores no customer data, and generates the same output whenever it receives the same input.
What you can do with it
Prepare a services proposal
Calculate workshops, implementation days, and support packages in one consistent quote summary.
Quote product quantities
Turn unit prices and quantities into reviewed line totals before rendering a customer-facing document.
Automate sales approvals
Create stable quote data that exposes the subtotal, concession, total, and validity period to an approval workflow.
FAQ
Is the discount a percentage?
No. The discount is a fixed monetary amount in the quote currency.
Does the generator calculate tax?
No. It calculates line totals, subtotal, fixed discount, and final total only.
Does the validity period contain an expiration date?
No. It returns a deterministic number of validity days so your system can combine it with the actual issue date.
Can I list an included deliverable at no charge in the quote?
Yes. A line with a price of zero documents an included deliverable or complimentary service without changing the subtotal, so the customer sees the full scope of the offer.
What happens if the discount is larger than the subtotal?
The quote is not produced. Instead of returning a negative total, a fixed discount above the subtotal is rejected, which also catches a stale discount left over after the line items changed.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/doc/quote-estimate-generate \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"items":[{"description":"Discovery workshop","price":450,"quantity":1},{"description":"Implementation day","price":800,"quantity":3}]}'const res = await fetch("https://api.kit.forhosting.com/doc/quote-estimate-generate", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"items": [
{
"description": "Discovery workshop",
"price": 450,
"quantity": 1
},
{
"description": "Implementation day",
"price": 800,
"quantity": 3
}
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/doc/quote-estimate-generate",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"items": [
{
"description": "Discovery workshop",
"price": 450,
"quantity": 1
},
{
"description": "Implementation day",
"price": 800,
"quantity": 3
}
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/doc/quote-estimate-generate", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"items":[{"description":"Discovery workshop","price":450,"quantity":1},{"description":"Implementation day","price":800,"quantity":3}]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"items":[{"description":"Discovery workshop","price":450,"quantity":1},{"description":"Implementation day","price":800,"quantity":3}]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/doc/quote-estimate-generate", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"items": [
{
"description": "Discovery workshop",
"price": 450,
"quantity": 1
},
{
"description": "Implementation day",
"price": 800,
"quantity": 3
}
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "doc.quote_estimate_generate",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_mb | 25 |
max_pages | 200 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
The result is deterministic JSON that can feed an approval flow, customer portal, document renderer, email template, or internal record while keeping the underlying arithmetic easy to inspect.
Apply the discount and verify the totals
When it exceeds the subtotal, the request returns an invalid-input error instead of producing a negative quote total. That guard is especially helpful when discount values come from a CRM field or an automated sales rule and could be stale after line items change. Before sending a quote, compare the returned summary with the commercial approval: subtotal shows the value before concessions, discount_amount exposes the concession clearly, and total is the amount proposed to the customer.
Use the structured document and validity period
Use the returned JSON directly in a customer portal, map it into a branded document template, attach it to an opportunity record, or send it through an approval workflow.
Technical questions
What does one request cost?
Each request costs $0.002.
What happens if the discount is larger than the subtotal?
The request returns an invalid-input error and no quote document is produced.