{"schema":"comptoir.guide/v1","version":"0.5.2","tagline":"the billing + declarative-compute spine for a family of small calculators","model":{"product":"A product is a CONFIG ROW, not a repo: a declarative ruleset (bands, guards, surcharges, fees, derived values), a price, an email template and a report template.","serving":"One binary serves them all at /p/<slug>/*. Adding a product adds no port, no systemd unit, no DNS record and no deploy.","truth":"git is the source of truth; the sqlite db is the deployed cache."},"product_dir":{"products/<slug>/product.json":"price, email, deliver, limits, public_url","products/<slug>/ruleset.json":"the engine","products/<slug>/cases.json":"GOLDEN CASES — apply refuses if any fail","products/<slug>/report.html":"the paid deliverable template ({{placeholders}})"},"loop":["comptoir verify products/<slug>     — cases + structural validation, no writes","comptoir apply products/<slug>      — same, then upsert (refuses on failure)","comptoir product status <slug> live — draft routes 404 publicly until promoted","comptoir bundle <slug> > index.html — the artifact; it CALLS /calc, band tables never ship to the browser"],"why_golden_cases_are_mandatory":"A row computes money. Bands that overlap or leave a gap produce a wrong tax with NO error at all, so apply runs every case first and refuses to store config that fails one. Validation additionally rejects: non-contiguous bands, a guard falling back to a missing table, surcharge conditions that are not declared inputs, unknown derived ops, and anything that looks like a secret (config lives in git; credentials belong in comptoir's env).","http":{"GET|POST /p/<slug>/calc":"the computation, JSON, CORS-enabled","GET /p/<slug>/llms.txt":"generated from the row","GET /p/<slug>/guide":"generated","GET /p/<slug>/help-json":"generated","POST /p/<slug>/checkout":"Stripe Checkout url","GET /p/<slug>/verify":"is a key valid","POST /p/<slug>/deliver":"key-gated; renders + publishes to hart","POST /p/<slug>/email":"send the caller their own breakdown; captures the address","POST /stripe/webhook":"one endpoint, all products, HMAC + idempotent","GET /guide":"this document","GET /help-json":"the command catalog","POST /feedback":"tell the operator something is wrong; open, content-deduped"},"env":"COMPTOIR_DB, COMPTOIR_PUBLIC_URL, COMPTOIR_ADMIN_TOKEN (exercise drafts), STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, RESEND_API_KEY, COMPTOIR_FROM, HART_OWNER_KEY, HART_URL. Secrets live HERE, never in a product row.","gotchas":["Rates are basis points parsed from decimal strings: an integer-percent engine silently truncates 7.5% to 7% and bills the wrong tax.","A draft product 404s publicly; promote with product status <slug> live.","One purchase unlocks the BUNDLE it was sold for (uk-tax, fr-immo, ...), not just the product bought from, and not other bundles.","The artifact calls /calc — it does not embed the ruleset, so band tables never reach the browser."],"stdout":"data only (JSON)","stderr":"context and typed errors only","errors":"{ok:false,error:{code,type,message,recoverable,suggestions}} on stderr","exit_codes":{"0":"ok","80-89":"input/validation","90-99":"resource","100-109":"integration","110-119":"internal"},"update":"NOT APPLICABLE. comptoir is a privately deployed service, not a distributed binary — there are no third-party installs to self-update. It ships via deploy.sh, which builds from source, runs every product's golden cases and refuses to deploy if one fails. The CLI update spec targets tools users install; this is not one."}