Documentation

Proposal Templates API

Manage proposal templates and generate professional proposals from project data.

GET /api/v1/proposal-templates

List all proposal templates for the current tenant.

Response

{
    "success": true,
    "data": {
        "templates": [
            {
                "id": 1,
                "name": "Standard AV Proposal",
                "description": "Default template for AV proposals",
                "isDefault": true,
                "sourceType": "manual",
                "createdAt": "2024-01-15T10:30:00Z",
                "updatedAt": "2024-01-20T14:15:00Z"
            }
        ],
        "totalCount": 1
    }
}

GET /api/v1/proposal-templates/{id}

Get a single proposal template including its full HTML content.

Response

{
    "success": true,
    "data": {
        "template": {
            "id": 1,
            "name": "Standard AV Proposal",
            "description": "Default template for AV proposals",
            "content": "<h1>{project.name}</h1><p>Prepared for {client.company}...</p>",
            "isDefault": true,
            "sourceType": "manual",
            "createdAt": "2024-01-15T10:30:00Z",
            "updatedAt": "2024-01-20T14:15:00Z"
        }
    }
}

POST /api/v1/proposal-templates

Create a new proposal template.

Request Body

Field Type Required Description
name string Yes Template name (max 200 chars)
description string No Brief description of the template purpose
content string Yes HTML template content with variable placeholders (e.g., {project.name})
isDefault boolean No Set as default template for new proposals (default: false)

Example Request

{
    "name": "Conference Room Proposal",
    "description": "Template for conference room projects",
    "content": "<h1>{project.name}</h1><p>Prepared for {client.company}</p>{#foreach room}<h2>{room.name}</h2>{room.equipment}{/foreach}",
    "isDefault": false
}

Response (201 - Created)

Returns the created template with its assigned ID.


PUT /api/v1/proposal-templates/{id}

Update an existing proposal template. All fields are optional - only provided fields are updated.

Request Body

Field Type Required Description
name string No Template name (max 200 chars)
description string No Brief description of the template purpose
content string No HTML template content with variable placeholders
isDefault boolean No Set as default template (removes default from other templates)

Example Request

{
    "name": "Updated Template Name",
    "content": "<h1>{project.name}</h1>...updated content...",
    "isDefault": true
}

DELETE /api/v1/proposal-templates/{id}

Delete a proposal template.

Response

{
    "success": true,
    "data": {
        "id": 1,
        "name": "Deleted Template",
        "deleted": true
    }
}

POST /api/v1/proposal-templates/{id}/set-default

Set a template as the default for the tenant. Only one template can be default.

Response

Returns the updated template with isDefault: true.

POST /api/v1/proposal-templates/{id}/preview

Preview a template with sample data. Useful for testing variable substitution without a project.

Response

{
    "success": true,
    "data": {
        "templateId": 1,
        "templateName": "Standard AV Proposal",
        "html": "<h1>Sample Project Name</h1><p>Prepared for Acme Corporation...</p>",
        "usedSampleData": true
    }
}
Block-builder templates

A block-builder template returns a complete themed HTML document — styled cover page, theme CSS, and equipment cards — in html. Add ?format=body to the request URL to get the bare content instead. Classic HTML templates always return body-only and ignore format.

POST /api/v1/proposal-templates/{id}/generate

Generate a proposal by applying the template to a specific project. Substitutes all variables with actual project data.

Request Body

Field Type Required Description
projectId integer Yes ID of the project to use for variable substitution

Example Request

{
    "projectId": 123
}

Response (200 - Success)

{
    "success": true,
    "data": {
        "templateId": 1,
        "templateName": "Standard AV Proposal",
        "projectId": 123,
        "html": "<h1>Corporate Conference Room</h1><p>Prepared for Acme Corp...</p>",
        "variablesUsed": ["project.name", "client.company", "room.name", "room.equipment"]
    }
}
Block-builder templates

A block-builder template returns a complete themed HTML document (cover page + theme styling) in html, and variablesUsed comes back as an empty array. Add ?format=body for the bare themed body. Classic HTML templates return body-only with the substituted variable list.

GET /api/v1/proposal-templates/variables

Get all available template variables with descriptions and sample values.

Response

{
    "success": true,
    "data": {
        "variables": [
            {
                "path": "project.name",
                "displayName": "Project Name",
                "description": "The name of the project",
                "category": "Project",
                "sampleValue": "Sample Project Name",
                "syntax": "{project.name}",
                "requiresRoomName": false,
                "isLoopSyntax": false,
                "isLoopVariable": false
            },
            {
                "path": "room.equipment",
                "displayName": "Room Equipment Table",
                "description": "Equipment table for current room (use in room loop)",
                "category": "Room",
                "sampleValue": "[Equipment Table]",
                "syntax": "{room.equipment}",
                "requiresRoomName": false,
                "isLoopSyntax": false,
                "isLoopVariable": true
            }
        ],
        "byCategory": {
            "Project": [...],
            "Client": [...],
            "Room": [...],
            "Date": [...]
        },
        "totalCount": 70
    }
}

Variable Categories

Category Description Example Variables
Project Project-level information and totals {project.name}, {project.total}, {project.jobNumber}
Client Client/customer information {client.company}, {client.contact}, {client.email}
Room Room-level data (use inside loops) {room.name}, {room.equipment}, {room.total}
Date Date formatting {date.today}, {date.year}
All Rooms Aggregated data across all rooms {all.equipment}, {all.summary}

Room Loop Syntax

Use {#foreach room}...{/foreach} to iterate over rooms:

<h1>{project.name}</h1>
<p>Prepared for {client.company}</p>

{#foreach room}
<h2>{room.name}</h2>
<p>Room {room.index} of {room.quantity}</p>
{room.equipment}
{room.pagebreak}
{/foreach}

<h2>Project Total: {project.totalWithTax}</h2>
Equipment Column Customization

Use {room.equipment:Description,Make,Model,Qty,Extended} to specify which columns appear in equipment tables. Available columns: Description, Make, Model, Notes, Qty, Rate, Extended.

Add/Alt Rooms

Use {#foreach addalt}...{/foreach} to iterate over Add/Alt rooms separately from regular rooms.