On this page

Commercial proposal

A multi-page proposal built from blocks: a cover with your client, scope, plans, pricing and a closing page.

propuesta-comercial: the document you use to present a service, not the one that quotes a price. For that there is the quote, which fits on one page. This one takes as many as it needs: a cover with your client’s name, the sections you send, and a closing page with your contact details.

It is a block-based document. You build the sequence in secciones; each one is drawn according to its tipo and paginated in order. The business vocabulary —“250 units”, “Monthly plan”, “24 business hours”— travels in the data, so the same proposal works for a homeowners’ association, a chain of branches or any other service.

"issuer": { "name": "PIENSA IT", "nit": "902001989-5", "phone": "…", "email": "…", "web": "…", "logo": "https://…/logo.png" },
"portada": {
  "rotulo": "PROPOSAL 2026",
  "linea": "SERVICES FOR PROPERTY MANAGEMENT",
  "titulo": "Clear billing.\nCalm operations.",
  "entrada": "We process, verify and deliver your monthly billing…",
  "rotuloDelCliente": "PROPOSAL PREPARED FOR",
  "cliente": { "nombre": "Los Almendros Residences", "magnitud": "250 units", "nota": "Proposed plan" },
  "numero": "PC-2026-014", "version": "2", "fecha": "2026-09-29", "vigencia": "Valid for 30 days"
},
"fondoTenue": "torres",
"secciones": [ /* see below */ ],
"cierre": {
  "despedida": "Thank you for considering us",
  "titular": "We are ready to build a clear and efficient operation.",
  "rotuloDeContacto": "LET'S TALK",
  "contactos": ["3125655293", "[email protected]", "www.piensait.com"]
}
  • Required: portada.titulo, portada.cliente.nombre and secciones with at least one entry. If any is missing, the response is a 400 with faltan, giving the exact path —secciones[2].total.valor— and nothing is rendered.
  • The file is named Propuesta_<portada.numero>_v<portada.version>.pdf, without accents or spaces, sin-numero when the number is missing and no _v… when there is no version.
  • portada.version also prints next to the number on the cover. A proposal gets renegotiated, and without a version two PDFs for the same client are indistinguishable.
  • Pages are 960 x 540 points (16:9), not A4: a proposal is shown on a screen and paged through.
  • fondoTenue puts one of the photos, very faint, behind the content pages, with velaDelFondoTenue between 0.02 and 0.2 (0.08 by default).

The sections

Every section accepts rotulo, titular, bajada, nota and nuevaHoja. Each section starts a new page unless it carries "nuevaHoja": false, which joins it to the previous one. A section that does not fit splits by itself.

tipo What it draws Its own fields
tarjetas A grid of title + text cards items[{titulo,texto}], columnas (1 to 3, 3 by default), numerar (true by default), franja, remate
lista One-line rows items (strings), numerar
pasos Numbered steps items[{titulo,texto}], destacado:{rotulo,texto}
tarifa One pricing option cifra:{rotulo,valor}, filas[{concepto,valor}], total:{rotulo,valor}
comparativa Plans side by side planes[{nombre,distintivo}], filas[{caracteristica,valores[]}], precios[{rotulo,valores[]}]
texto Rich text cuerpo (restricted HTML with placeholders), valores, catalogo
separador A photo band that heads the block below it fondo, velo

Optional services are tarjetas with "columnas": 1 and "numerar": false. There is no separate type for that.

Photos

The cover and separador sections accept fondo: a full-bleed photo with a veil of the design’s colour on top, so the text stays readable. It takes a URL or a data: with the property’s own photo —that one wins— or the name of one of the built-in backgrounds: torres, balcones and reticula. It must be PNG or JPEG; an SVG is drawn at its original size and comes out cropped.

velo is the opacity of the colour over the photo, from 0.55 to 1, and 0.78 by default. Below 0.55 it is not accepted: a bright sky leaves a white headline unreadable, and that is not something the engine can check the way it checks the contrast of two flat colours.

A separador is a full page, like the cover and the closing page: a block’s half-title. With no photo it falls back to the accent colour, which still works as a breather. The cover and the closing page are also in the brand colour, with the issuer’s logo, and carry no footer.

{ "tipo": "separador",
  "rotulo": "WHAT IT COSTS",
  "titular": "Two plans, the same scope",
  "bajada": "Pick how you want to pay for it; what you get does not change.",
  "fondo": "reticula" }
{ "tipo": "tarifa",
  "rotulo": "Monthly plan",
  "titular": "Month-to-month flexibility",
  "cifra": { "rotulo": "RATE PER INVOICE ISSUED", "valor": "$1,770" },
  "filas": [ { "concepto": "Number of units", "valor": "250" },
             { "concepto": "Monthly amount", "valor": "$442,500" } ],
  "total": { "rotulo": "MONTHLY TOTAL BEFORE TAX", "valor": "$442,500" },
  "nota": "Commercial minimum: 30 units. Amounts before tax." }

Amounts arrive already worked out

Values are text and are printed exactly as they arrive, with their currency and separators. Nothing here multiplies the rate by the quantity or adds up the rows: that is why total.valor is required. A total that does not match its rows is printed all the same, because whoever sends the figure is the one answering for it.

The cuerpo of a texto section accepts the same restricted HTML as contracts —h1 to h3, p, ul, ol, li, hr, table, strong, em, u, br— and the {"{{key}}"} placeholders, filled in from valores.

Designs: violeta —the default—, grafito, moderna, clasica and corporativa. Same layout, different colour, and all of them stylable.

Full example: propuesta-comercial.json.