Bridge Methods
Read Methods
Section titled “Read Methods”All read methods are available to both standalone and quoting_extension tool types.
context.get()
Section titled “context.get()”Returns the current user and tenant context.
const ctx = await window.pipeline.context.get();// Returns:// {// userName: "Jane Smith",// userEmail: "jane@example.com",// userRole: "H_Admin",// tenantName: "Acme Corp",// tenantId: "abc-123",// cultureCode: "en-NZ"// }customers.list(options?)
Section titled “customers.list(options?)”Returns a paginated list of customers.
const result = await window.pipeline.customers.list({ page: 1, pageSize: 50 });// Returns:// {// items: [{ id: "...", name: "John Doe", email: "john@example.com", phone: "021..." }],// totalCount: 150,// page: 1,// pageSize: 50// }products.list(options?)
Section titled “products.list(options?)”Returns a paginated list of products/services. The sku field is the human-readable
product code from Stock_SKU.SKU - use this for stable cross-environment product
references (GUIDs can vary between environments).
const result = await window.pipeline.products.list({ page: 1, pageSize: 50 });// Returns:// {// items: [// { id: "a1b2c3d4-...", sku: "WGT-001", name: "Widget A", price: 29.99, unit: "T_ITEM" }// ],// totalCount: 42,// page: 1,// pageSize: 50// }Response item fields: id (GUID), sku (human-readable code), name, price (retail sell price), unit (UOM token).
taskTemplates.list(options?)
Section titled “taskTemplates.list(options?)”Returns task templates from G_Task_Templates, filtered to active rows in the current tenant.
Use this to resolve a task template’s code (e.g. T_DEFAULT_INSTALLATION_TASK) to its GUID
so the GUID can be passed as linkedItemId on a lineType: "task" line in quotes.addLines.
When codes is provided, page/pageSize are ignored and all matching rows are returned.
When codes is omitted, results paginate the full active task-template list.
const result = await window.pipeline.taskTemplates.list({ codes: ["T_DEFAULT_INSTALLATION_TASK", "T_DEFAULT_REMOVAL_TASK"]});// Returns:// {// items: [// { id: "8a9d034f-...", code: "T_DEFAULT_INSTALLATION_TASK", name: "T_DEFAULT_INSTALLATION_TASK" }// ],// totalCount: 2,// page: 1,// pageSize: 50// }Request fields: codes (string[], optional), page (number, optional), pageSize (number, optional).
Response item fields: id (GUID), code (stable token), name.
costItems.list(options?)
Section titled “costItems.list(options?)”Returns cost-of-business items from COB_Items, filtered to active rows in the current tenant.
Use this to resolve a COB item’s code (e.g. COS-TRAVEL-TIME, COS-SITE-VISIT) to its GUID
for use as linkedItemId on a lineType: "cost" line.
const result = await window.pipeline.costItems.list({ codes: ["COS-TRAVEL-TIME", "COS-SITE-VISIT", "COS-SHIPPING", "COS-DISPOSAL"]});// Returns:// {// items: [// { id: "95abe0dc-...", code: "COS-TRAVEL-TIME", name: "Travel time", type: "T_TRAVEL" }// ],// totalCount: 4,// page: 1,// pageSize: 50// }Request fields: codes (string[], optional), page (number, optional), pageSize (number, optional).
Response item fields: id (GUID), code (stable token), name, type (COB_Items.T_Type token, e.g. "T_FINANCIAL", "T_TRAVEL").
jobCostTemplates.list(options?)
Section titled “jobCostTemplates.list(options?)”Returns job-cost templates from JobCostTemplate, filtered to active rows in the current tenant
and ordered by CostCode. This is the modern replacement for costItems.list:
use it to resolve a template’s code (e.g. SHIPPING, DISPOSAL, TRAVEL, CHECK-MEASURE) to
its GUID for use as linkedItemId on a lineType: "jobcost" line.
When the resolved GUID is passed back as linkedItemId, the host routes the line’s GL via the
template’s cost code; the extension-supplied unitPrice / costPrice always win (the template
contributes classification and GL routing only, not pricing).
When codes is provided, page/pageSize are ignored and all matching rows are returned.
When codes is omitted, results paginate the full active job-cost-template list.
const result = await window.pipeline.jobCostTemplates.list({ codes: ["SHIPPING", "DISPOSAL", "TRAVEL", "CHECK-MEASURE"]});// Returns:// {// items: [// { id: "95abe0dc-...", code: "SHIPPING", name: "Shipping", type: "T_PURCHASED_ITEM" }// ],// totalCount: 4,// page: 1,// pageSize: 50// }Request fields: codes (string[], optional), page (number, optional), pageSize (number, optional).
Response item fields: id (GUID), code (JobCostTemplate.CostCode), name (CostName), type (T_CostType token: "T_ADHOC" | "T_PURCHASED_ITEM" | "T_THIRD_PARTY_COST" | "T_EXPENSE").
jobs.list(options?)
Section titled “jobs.list(options?)”Returns a paginated list of active jobs for the tenant. Available to all tool types.
const result = await window.pipeline.jobs.list({ page: 1, pageSize: 50 });// Returns:// {// items: [// {// id: "e5f6a7b8-...",// ref: "JOB-0042",// customerName: "Acme Corp",// customerIdGuid: "c1d2e3f4-...",// status: "InProgress"// }// ],// totalCount: 12,// page: 1,// pageSize: 50// }Response item fields: id (GUID), ref (human-readable job reference), customerName, customerIdGuid (GUID), status.
quotes.list(options?)
Section titled “quotes.list(options?)”Returns a paginated list of quotes.
const result = await window.pipeline.quotes.list({ page: 1, pageSize: 50 });// Returns:// {// items: [{ id: "...", ref: "QR-001", customerName: "John Doe", total: 115.00, status: "Draft", date: "2026-04-16T00:00:00" }],// totalCount: 25,// page: 1,// pageSize: 50// }Write Methods
Section titled “Write Methods”quotes.create(request)
Section titled “quotes.create(request)”Creates a new quote in Vera. Available to all tool types.
Marketplace tools do NOT need API keys or inbound tokens - the bridge handles all authentication through the current user’s Vera session.
const result = await window.pipeline.quotes.create({ customerName: "John Doe", customerEmail: "john@example.com", customerPhone: "021 123 4567", upsertByEmail: true, title: "Quick Quote", quoteRef: "", lines: [ { description: "Widget A", productCode: "WGT-001", qty: 2, unitPrice: 29.99, taxRate: 0.15 } ]});// Returns:// {// id: "abc-123-...",// ref: "QR-042",// total: 68.98// }Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
| customerName | string | No | Customer display name |
| customerEmail | string | Conditional | Required when upsertByEmail is true |
| customerPhone | string | No | Customer phone number |
| upsertByEmail | boolean | No | If true, creates or matches customer by email |
| title | string | No | Quote title |
| quoteRef | string | No | Custom quote reference |
| lines | array | Yes | At least one line item required |
Line item fields:
| Field | Type | Required | Description |
|---|---|---|---|
| description | string | No | Line item description |
| productCode | string | No | Product code reference |
| qty | number | Yes | Quantity (1-10000) |
| unitPrice | number | Yes | Unit price (0-1000000) |
| taxRate | number | Yes | Tax rate as decimal (e.g. 0.15 for 15%) |
Validation rules:
- Lines array must not be empty
- Maximum 200 line items per quote
- Quantity must be
> 0and<= 10,000 - Unit price must be
>= 0and<= 1,000,000
quotes.addLines(lines)
Section titled “quotes.addLines(lines)”Available to quoting_extension tools only.
Appends one or more lines to the currently-open quote. No server round-trip - the host
merges the lines into its in-memory quote and the user saves normally. Calling this method
from a standalone tool will return an error.
await window.pipeline.quotes.addLines([ // Product line (default lineType): generic SKU, with section grouping { description: "Roller blind - Main Lounge", productCode: "BLIND", qty: 1, unitPrice: 480.00, costPrice: 290.00, taxRate: 15, location: "Main Lounge", specification: "Linesque Fleece, 1200×1500, Inside fit", unit: "T_ITEM", groupKey: "blind-1", lineType: "product", linkedItemId: "a1b2c3d4-...", // Stock_SKU.IdGuid - replaces productId supplierRef: "WINDOWARE", // resolved against G_Suppliers (drives PO on quote-to-job) discountPercent: 10, // RRP unitPrice, nets back to the real selling price section: "Blinds" }, // Task line: explicit installation task { description: "Installation", qty: 1, unitPrice: 95.00, costPrice: 95.00, taxRate: 15, unit: "T_ITEM", lineType: "task", linkedItemId: "8a9d034f-...", // G_Task_Templates.IdGuid section: "Installation" }, // Job-cost line: shipping pass-through (template-linked) { description: "Shipping (standard)", qty: 1, unitPrice: 20.00, costPrice: 20.00, taxRate: 15, unit: "T_ITEM", lineType: "jobcost", linkedItemId: "eaaebd29-...", // JobCostTemplate.IdGuid (from jobCostTemplates.list) section: "Extras" }]);BridgeAddLineDto fields:
| Field | Type | Required | Description |
|---|---|---|---|
| description | string | optional | Free-text line description. Displayed as the line name in the quote. |
| productCode | string | optional | Human-readable SKU/code. Stored as WorkObjectCode on the quote line. |
| qty | number | required | Line quantity. Must be > 0. |
| unitPrice | number | required | Retail/sell price per unit. Markup must already be applied - the host does not re-mark up. |
| costPrice | number | optional | Buy/cost price per unit. When provided: BUY column = costPrice, SELL column = unitPrice (real margin visible in COB panel). When omitted: both BUY and SELL use unitPrice. |
| taxRate | number | required | Tax rate. Accepted as percentage (e.g. 15) or decimal fraction (e.g. 0.15) - the host normalises. |
| location | string | optional | Location or zone label. Maps to QuoteLine.FreeTextField2. Use for room, area, or zone labels (e.g. "Patio", "Living Room"). |
| specification | string | optional | Configuration or specification detail. Maps to QuoteLine.FreeTextField. Use for dimensions, colours, or model info. |
| unit | string | optional | Unit of measure token. Valid values: "T_ITEM" (default), "T_SQUARE_METRE" (m²), "T_LINEAR_METRE" (lm). |
| groupKey | string | optional | Arbitrary stable string identifier. Lines sharing the same groupKey receive the same QuoteLine.GroupId on the host, keeping related lines visually grouped within their section. Lines without a groupKey are ungrouped (GroupId = 0). |
| lineType | string | optional | One of "product" | "task" | "cost" | "jobcost". Defaults to "product". Selects which Vera table linkedItemId resolves into - see “Four line kinds” below. |
| linkedItemId | string (GUID) | optional | GUID into Stock_SKU / G_Task_Templates / COB_Items / JobCostTemplate based on lineType. Replaces productId for new tools. For product / task / cost the whole addLines batch is rejected if the GUID does not resolve to an active row in the indicated table. For jobcost, linkedItemId is optional (null = ad-hoc job cost, materialised on quote-to-job conversion). |
| section | string | optional | Categorical section label (e.g. "Blinds", "Motorisation", "Installation", "Extras", "Removal"). The host quote UI groups lines visually by section. Max 100 chars; trimmed; null/empty renders under “Ungrouped”. Section identity is the pair (section, summaryOnly). |
| summaryOnly | boolean | optional | Default false. When true, the section this line belongs to renders on customer-facing output as a single name + total row, with its individual lines suppressed. Lines are unaffected everywhere else - editor, job costing, grand total. Lines sharing a section but differing on summaryOnly resolve to two separate sections, so set it identically across a section’s lines. |
| sectionNotes | string | optional | Customer-facing note for this line’s section, printed under the section heading on the quote (including when the section is summaryOnly). Plain text; line breaks are kept; max 2000 chars. Not part of section identity - the first non-empty value among a section’s lines wins, so later lines need not repeat it. |
| discountPercent | number | optional | Per-line discount percentage (0-100). When set, the host stores it on QuoteLine.DiscountPercent and computes LineNett = sell × qty × (1 − discountPercent/100). Lets a tool pass an inflated RRP unitPrice with a discount that nets back to the real selling price. Null = 0 (no discount). |
| supplierRef | string | optional | Supplier identifier. Resolved host-side case-insensitively against G_Suppliers.SupplierRef, then G_Suppliers.Name (active suppliers only). Null or unresolved falls back to the Self supplier (T_SELF). A resolved supplier drives purchase-order and supplier-invoice creation after quote-to-job conversion. |
| freeTextField3 | string | optional | Free-text slot persisted onto QuoteLine.FreeTextField3 (fields 1 and 2 are populated from specification / location). Use to stash source-system metadata with nowhere else to go. On quote-to-job conversion, the four free-text fields map 1:1 to JobCost.FreeTextLine1-4. |
| freeTextField4 | string | optional | Free-text slot persisted onto QuoteLine.FreeTextField4. See freeTextField3. |
| productId | string (GUID) | deprecated | Use linkedItemId with lineType="product" instead. Retained for back-compat with Ziptrak v2.1.2 and earlier. When set without linkedItemId, behaves as linkedItemId with lineType="product" - triggers task-sequence auto-injection if the SKU has one configured. |
Four line kinds (lineType → linkedItemId target table):
lineType |
Target table | Behaviour |
|---|---|---|
"product" (default) |
Stock_SKU.IdGuid |
If the linked SKU has a task sequence configured, the host auto-injects its task template lines (e.g. installation tasks). |
"task" |
G_Task_Templates.IdGuid |
The line is the task. No auto-injection. Use taskTemplates.list to resolve codes to GUIDs. |
"cost" (deprecated) |
COB_Items.IdGuid |
Legacy cost-of-business line. No auto-injection. Superseded by "jobcost" - prefer that for new tools. Use costItems.list to resolve codes to GUIDs. |
"jobcost" |
JobCostTemplate.IdGuid (optional) |
Cost category (shipping, disposal, travel, check-measure) or an ad-hoc import line. No auto-injection. Template-linked when linkedItemId is set - GL routed via the template’s cost code, extension-supplied price wins. Ad-hoc when linkedItemId is null - the job-cost record is materialised on quote-to-job conversion (use for imports whose products don’t map to the catalogue). Use jobCostTemplates.list to resolve codes to GUIDs. |
Validation: the host rejects the entire addLines batch if any line has an unknown lineType or a non-null linkedItemId that does not resolve to an active row in the indicated table. A jobcost line with a null linkedItemId is valid (ad-hoc). summaryOnly is never a validation failure - it defaults to false when absent or non-boolean. A section longer than 100 chars is truncated, not rejected. Failures surface to the extension as an exception from addLines.
Sections with no lines
Section titled “Sections with no lines”A section usually comes into existence because a line names it. To add a section that has no lines of its own - an “Optional Extras” section whose content is a list of add-ons, for example - pass it in options.sections, or call quotes.addSections(sections), which is the same call with no lines.
await window.pipeline.quotes.addLines(lines, { sections: [ { name: "Optional Extras", notes: "Motorisation - add $180 per blind\nBlockout lining - add $45 per blind" } ]});
// Or on its own:await window.pipeline.quotes.addSections([ { name: "Optional Extras", notes: "Motorisation - add $180 per blind" }]);| Field | Type | Required | Description |
|---|---|---|---|
| name | string | required | Section label. Max 100 chars; longer names are truncated. |
| summaryOnly | boolean | optional | Default false. Part of section identity, exactly as on a line. |
| notes | string | optional | Printed under the section heading. Plain text; line breaks are kept; max 2000 chars. |
Declared sections are applied after the lines, so a new one lands after every section the lines created - which is where “Optional Extras” belongs. A declared section whose (name, summaryOnly) matches one the lines already created is not duplicated; its notes fill in the existing section only if that section has none yet.
On the customer’s quote, a section with notes but no lines prints its name and notes, with no subtotal or total. A section with neither lines nor notes is not printed.
A declared section with a blank name rejects the whole batch, lines included.