How it works
Every form has the same shape. First come the niche's own steps (for example "About the Trees"), then an optional photo step, then the shared contact step (name, phone, email, address with map pin, date, time and note), and finally the send buttons.
The niche file only describes its own steps and how things are worded. Saving requests, emails, WhatsApp messages, the quote page, the PDF and the dashboard all work the same for every niche.
packs/<id>/pack.json. Niches imported from the dashboard (Niche library → Import niche) are stored privately in data/niches/<id>.json. An imported niche with the same id as a built-in one replaces it, and that is how updates are installed. Restore original brings the built-in one back.Quick start
The easiest way to make a niche is to start from an existing one. Go to Niche library, open the ⋯ menu on a similar niche and choose Export file. Change the id, name and ref_prefix, edit the questions, then import it. This is a complete minimal niche:
{
"format": "rfq-niche",
"format_version": 1,
"id": "window-cleaning",
"version": "1.0.0",
"requires": "1.2",
"name": "Window Cleaning",
"category": "Home improvement",
"description": "Window cleaning: property type, windows and frequency.",
"ref_prefix": "WC",
"icon": "home",
"steps": [{
"id": "windows",
"title": "About Your Windows",
"nav": "Windows",
"intro": "A rough idea is enough.",
"fields": [
{ "name": "property", "label": "Property type", "type": "segment", "required": true,
"options": { "house": "House", "flat": "Flat", "office": "Office" } },
{ "name": "windows", "label": "Roughly how many windows?", "short": "Windows", "type": "segment", "required": true,
"options": { "s": "Up to 10", "m": "11–25", "l": "More than 25" } },
{ "name": "frequency", "label": "How often?", "type": "segment",
"options": { "once": "One-off", "monthly": "Monthly", "quarterly": "Every 3 months" } }
]
}],
"photos": null,
"title": "{property} · {windows}",
"assess": { "windows": { "label": "Size", "levels": { "s": "good", "m": "info", "l": "hot" } }, "@date": [], "@location": [] },
"defaults": { "hero_title": "Get a {Free Window Cleaning Quote}" }
}
Top-level keys
| Key | Required | What it does |
|---|---|---|
format, format_version | yes | Always "rfq-niche" and 1. |
id | yes | 2–40 lowercase letters, numbers or dashes, e.g. "roofing". Unique in the library. |
name | yes | Shown in the library and as the default business name. |
ref_prefix | yes | 2–3 capital letters for request numbers: RF → RF-261002-AB12. |
steps | yes | 1–6 form steps (see Questions). |
version | Your version of the file, e.g. "1.2.0". Shown in the library. | |
requires | The oldest quote system version the niche works with, e.g. "1.2". Newer niches are refused by older systems with a clear message. | |
category, description | Used for the library's filters and cards. | |
icon | One of: car truck trash skip tree home roof fence grass flower road brush box sofa solar sun zap ruler layers wrench tag clipboard. | |
photos | null for no photo step, or a photo step (see Photos). | |
contact | Changes to the shared contact step (see Contact step). | |
title | The request's title in lists and messages: a template using question names, e.g. "{load_size} · {items}". | |
specs | Question names shown in one line under the title. | |
assess, list_flags | The quick assessment cards and which of them appear as chips in the request list (see Quick assessment). | |
summary | Rows of the live summary beside the form: [["Label", "icon", ["question", …]], …]. | |
require_any | "Answer at least one of these": [{"fields": ["rooms", "paint_area"], "message": "…"}]. | |
status_labels | Rename statuses, e.g. {"booked": "Job booked"}. Keys: new contacted offer_sent booked completed lost. | |
words, defaults, landings | Wording, starter texts and extra landing pages (see Texts & wording). | |
art | {"hero": "…", "side": "…"}, SVG shapes for the banner (400×170) and the sidebar picture (320×150). |
Questions
Each step has an id (a lowercase word, not photos, contact or submit), a title, a short nav label for the progress bar, an intro line, and fields.
| Type | Looks like | Notes |
|---|---|---|
segment | Choice cards, pick one | Best for 2–8 short choices. Needs options. |
chips | Choice cards, pick several | Saved as "a,b". Needs options. |
select | Dropdown with search | For long lists. "free": true also accepts typed answers. |
text, number, email, tel, textarea | Input boxes | number accepts minnum, maxnum, unit, prefix. |
day | Row of upcoming dates | Usually you only rename the contact step's date. |
| Field key | What it does |
|---|---|
name | Lowercase letters, numbers and _. Unique, and not one of the contact names (full_name phone email location pickup_date pickup_time notes). |
label, short | The question, and an optional short label used in emails, lists and the quote page. |
options | {"key": "Label"}. Keys are stored with requests, so keep them stable once a niche is live. Labels can be changed any time. Labels may use {currency}. |
required | true / false. Business owners can also change this in Settings → Form fields. |
col | Width on a 12-column grid: 12 full, 6 half, 4 third. |
help, placeholder, icon | A hint under the question, a placeholder, and an icon inside text boxes. |
enabled | false = available in Settings → Form fields but switched off by default. |
Modules
Instead of a question, a field can use a ready-made module that adds several linked questions:
| Module | Adds | Options |
|---|---|---|
{"use": "vehicle"} | Make, Model (suggestions follow the make) and Year. | — |
{"use": "route", …} | Pickup and drop-off addresses with map pins, the road distance between them, and a date. The contact step's own address and date are removed automatically. | from, to, from_short, to_short, date, date_short, time (true/false), from_fields / to_fields (up to 4 questions under each address). |
{"use": "measure", …} | A length or area, typed in m/ft (m²/ft²), or drawn on a street or satellite map. | name, label, kind ("length" or "area"), draw (false = typing only), required, short, help. |
Photos
"photos": {
"title": "Photos of the Roof",
"intro": "photos of the roof and any damage help us quote accurately.",
"tip": "Tip: take a photo of the whole roof from the street…",
"error": "Please add at least one photo of the roof.",
"slots": {
"roof": { "label": "Whole roof", "art": "<path d=\"…\"/>" },
"damage": { "label": "Damage close-up", "art": "…" }
}
}
Up to 6 named tiles, plus "Add more photos". The minimum number of photos is set by the business in Settings. The art outline is drawn on an 80×56 grid.
Contact step
Rename or adjust the shared fields. Allowed changes are label, short, placeholder, help, required, plus "_step": {"title", "intro", "nav"}:
"contact": {
"_step": { "intro": "We'll use this to send you our quote." },
"location": { "label": "Property Address" },
"pickup_date": { "label": "Preferred Start Date", "short": "Start date" },
"notes": { "placeholder": "e.g. Access through the side gate…" }
}
Quick assessment
The coloured cards at the top of each request, in priority order (the first 6 are shown). Each entry is a question name, or one of the built-in cards @photos, @date, @location and @distance.
| Key | What it does |
|---|---|
label | Card title (default: the question's short label). |
levels | Answer → good (green), info (grey), warn (amber), bad (red) or hot (orange, urgent/valuable). Add "default" for the rest. With several answers, the most serious wins. |
text | Answer → wording on the card, e.g. {"road": "Road, permit needed"}. |
also | Show a second answer on the same card: {"from_lift": {"no": "warn"}} → "2nd floor · No lift". |
sizes | For measures: {"50": "good", "200": "info", "1000000000": "hot"}, in metres or m². |
long | For @distance: kilometres from which the trip is marked hot. |
Texts & wording
words
How the system talks about this niche. Keys: customer, customers, offer ("offer" when you pay the customer, "quote" when they pay you), about (e.g. "your {title}"), details, visit (the date's name, e.g. "Delivery"), another, wa_heading, contact_heading, next_steps (list), chat, completed.
defaults
Starter texts loaded when a business chooses the niche. They can then change them in Settings. Keys: business_name tagline hero_title hero_text usps why_title why_points help_title help_text art_text consent_text offer_template legal_text mail_from_name. In hero_title, {curly} words are highlighted. usps is three lines of Title | subtitle.
landings
Extra landing pages with their own banner, for ads or another service name: {"vehicle-transport": {"label": "…", "hero_title": "…", "hero_text": "…"}} → index.php?lp=vehicle-transport.
Import & updates
- Niche library → Import niche and choose the file. It is checked first. If something is wrong, you get a list like "step 1 › question 3 (gates): "options" must list the choices…" and nothing is changed.
- A new niche appears in the library. Press Preview to try the real form without switching (only you can see a preview, and it can't send requests).
- Press Use this niche to switch. Existing requests keep their original questions.
- To update a niche, import the new file with Replace ticked. Keep the option keys the same so older requests still read correctly.
Safety rules
- Niche files are data only. Nothing in them is ever run as code, and every value is checked against the rules above.
- Illustrations are cleaned down to plain shapes (
path circle rect ellipse line polyline polygon gand their drawing attributes). Scripts, links, styles, images and event handlers are removed. - Files are limited to 400 KB, and imported files are stored in the private
data/folder.