Proposal templates tools
Proposal templates covers proposal templates: their budgets, quote sections and lines, notes, custom rate cards, and the workflows that rebuild a budget or a quote.
Like Setup, this toolset is offered only on accounts where Drum has turned on account setup through the API.
Several tools here replace data: changing the budget structure, syncing the budget to the quote, rebuilding a deliverable from its template, and applying rate card rates. They are marked destructive, and an assistant should ask before it calls one.
The toolset also has:
search_recordsget_account_settingsandlist_settings_recordsdelete_recordandrestore_recordwith the proposal template kinds
Tools
Each tool below shows what the server sends: its description (written for the AI), its kind, the permissions it needs, the fields it returns, and its inputs. An input in a.b or a[].b form is a field inside an object or a list. For the shared rules on results, pages, money and errors, see Results, errors and limits.
get_proposal_template
Read one proposal template (a quote with no project) with its budget, quote sections, lines and notes, and the ids of all rows. Each row shows the keys that add_proposal_template_row and update_proposal_template_row take for its row type, and its record_kind for delete_record. Budget deliverables come in pages, so if budget.deliverables_page.has_more is true, call again with budget_deliverable_offset set to offset plus count. Budget items are concise, and response_format detailed adds their values, other fields and lines.
| Title | Get proposal template |
| Toolsets | Proposal templates |
| Kind | Read only, Idempotent |
| Needs | api_read, read_quotes and read_budgets |
| Returns | id, name, description, project_template, currency, default_sent_days, default_expiry_days, template_document, deleted, budget, notes, quote_sections, warnings |
| Input | Type | Required | Description |
|---|---|---|---|
proposal_template_id |
integer | Yes | From search_records with kinds proposal_template. |
budget_deliverable_ids |
array of integers | Only these budget deliverables. Ids from get_proposal_template. Default all. | |
budget_deliverable_offset |
integer | Number of budget deliverables to skip. Default 0. | |
response_format |
string | concise (default): id, record_kind, kind, name, item_type and position of each budget item. detailed adds the values, the other fields and the lines. One of concise, detailed. |
create_proposal_template
Create one proposal template (a quote with no project), with its notes, quote sections and lines, and budget phases, deliverables, items and lines if you send them. project_template_id first builds the budget and the matched sections from that project template, or copy_from_id copies a proposal template with all its rows. This tool only adds data: change the template with update_proposal_template and one row with the row tools. After a timeout, read the proposal templates with search_records before you try again. A budget needs the budget update permission. The result gives the ids of the new rows down to the items and quote lines, not of the item lines.
| Title | Create proposal template |
| Toolsets | Proposal templates |
| Kind | Writes data |
| Needs | api_create and create_quotes. A budget also needs update_budgets |
| Returns | id, name, description, project_template, currency, default_sent_days, default_expiry_days, template_document, deleted, budget, note_count, note_ids, quote_section_count, quote_sections, warnings |
| Input | Type | Required | Description |
|---|---|---|---|
copy_from_id |
integer | The proposal template to copy. From search_records with kinds proposal_template. | |
name |
string | Required unless copy_from_id is sent. Stored as the quote number. | |
description |
string | ||
project_template_id |
integer | Builds the budget. From search_records with kinds project_template. | |
currency |
string | ISO 4217 code. Default the account currency. | |
default_sent_days |
integer | Days. | |
default_expiry_days |
integer | Days. | |
template_document |
object | ||
template_document.filename |
string | Must end in .docx. | |
template_document.content_base64 |
string | The file, base64 encoded, 1 MB or less decoded. | |
template_document.from_proposal_template_id |
integer | Or copy its document. From search_records with kinds proposal_template. | |
notes |
array of objects | ||
notes[].content |
string | Yes | |
notes[].financial |
boolean | true for a financial note. | |
budget |
object | ||
budget.name |
string | ||
budget.description |
string | ||
budget.rate_card_id |
integer | An active account rate card, from search_records with kinds rate_card. | |
budget.reprice_resources |
boolean | Move the lines on the old card’s rate to rate_card_id. | |
budget.phases |
array of objects | ||
budget.phases[].name |
string | Yes | |
budget.phases[].description |
string | ||
budget.phases[].colour |
string | A phase colour. One of gray, red, orange, yellow, blue, green, indigo. |
|
budget.deliverables |
array of objects | ||
budget.deliverables[].name |
string | ||
budget.deliverables[].from_project_template_deliverable_ids |
array of integers | From list_settings_records with kind project_template_deliverable. | |
budget.deliverables[].description |
string | ||
budget.deliverables[].colour |
string | One of red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose. |
|
budget.deliverables[].budget_type |
string | One of fixed_price, time_and_materials. |
|
budget.deliverables[].budget_phase_id |
integer | A budget phase, from get_proposal_template. | |
budget.deliverables[].budget_phase_name |
string | Or a budget phase name. | |
budget.deliverables[].items |
array of objects | ||
budget.deliverables[].items[].kind |
string | fixed: quantity x rate. dynamic: sum of lines. One of fixed, dynamic, non_financial. |
|
budget.deliverables[].items[].name |
string | Yes | |
budget.deliverables[].items[].item_type |
string | One of task, event, process_only. |
|
budget.deliverables[].items[].description |
string | ||
budget.deliverables[].items[].delivery_task_name |
string | Its task name on a project. | |
budget.deliverables[].items[].quantity |
number | ||
budget.deliverables[].items[].quantity_unit |
string | One of hour, day, per_item. |
|
budget.deliverables[].items[].billable_rate_cents |
integer | Tax exclusive. | |
budget.deliverables[].items[].resources |
array of objects | ||
budget.deliverables[].items[].resources[].resource_type_id |
integer | From search_records with kinds resource_type. | |
budget.deliverables[].items[].resources[].preferred_member_id |
integer | From search_records with kinds member. | |
budget.deliverables[].items[].resources[].quantity |
number | ||
budget.deliverables[].items[].resources[].quantity_unit |
string | One of hour, day, per_item. |
|
budget.deliverables[].items[].resources[].rate_cents |
integer | Tax exclusive. Omit to use the rate cards. | |
budget.deliverables[].items[].resources[].notes |
string | ||
budget.deliverables[].items[].costs |
array of objects | ||
budget.deliverables[].items[].costs[].cost_type_id |
integer | Yes | From search_records with kinds cost_type. |
budget.deliverables[].items[].costs[].name |
string | Yes | |
budget.deliverables[].items[].costs[].description |
string | ||
budget.deliverables[].items[].costs[].quantity |
number | ||
budget.deliverables[].items[].costs[].quantity_unit |
string | One of hour, day, per_item. |
|
budget.deliverables[].items[].costs[].billable_rate_cents |
integer | Tax exclusive. | |
quote_sections |
array of objects | ||
quote_sections[].name |
string | ||
quote_sections[].description |
string | ||
quote_sections[].lines |
array of objects | ||
quote_sections[].lines[].line_item_code_id |
integer | From search_records with kinds line_item_code. | |
quote_sections[].lines[].name |
string | ||
quote_sections[].lines[].quantity |
number | ||
quote_sections[].lines[].price_cents |
integer | Tax exclusive. | |
quote_sections[].lines[].finance_account_id |
integer | From search_records with kinds finance_account. | |
quote_sections[].lines[].tax_rate_id |
integer | From search_records with kinds tax_rate. |
update_proposal_template
Change the fields of one proposal template and the settings of its budget (name, description, rate card). Omit a field to keep it, and send null to clear it. budget.custom_rate_card_id null stops using the custom rate card without deleting it. This tool does not change rows: use add_proposal_template_row, update_proposal_template_row and delete_record, and get_proposal_template reads them. project_template_id changes the link only and does not rebuild the budget. A budget change needs the budget update permission, and a finalised budget refuses it.
| Title | Update proposal template |
| Toolsets | Proposal templates |
| Kind | Writes data, Idempotent |
| Needs | api_update and update_quotes. A budget also needs update_budgets |
| Returns | id, name, description, project_template, currency, default_sent_days, default_expiry_days, template_document, deleted, budget, note_count, note_ids, quote_section_count, quote_sections, warnings |
| Input | Type | Required | Description |
|---|---|---|---|
proposal_template_id |
integer | Yes | From search_records with kinds proposal_template. |
name |
string | Stored as the quote number. | |
description |
string or null | null clears it. | |
project_template_id |
integer or null | From search_records with kinds project_template. null clears it. | |
currency |
string | ISO 4217 code. | |
default_sent_days |
integer or null | Days. null clears it. | |
default_expiry_days |
integer or null | Days. null clears it. | |
template_document |
object | ||
template_document.filename |
string | Must end in .docx. | |
template_document.content_base64 |
string | The file, base64 encoded, 1 MB or less decoded. | |
template_document.from_proposal_template_id |
integer | Or copy its document. From search_records with kinds proposal_template. | |
budget |
object | ||
budget.name |
string | ||
budget.description |
string or null | null clears it. | |
budget.rate_card_id |
integer | An active account rate card, from search_records with kinds rate_card. | |
budget.reprice_resources |
boolean | Move the lines on the old card’s rate to rate_card_id. | |
budget.custom_rate_card_id |
null | null stops using the custom rate card. |
add_proposal_template_row
Add one row to a proposal template. row_type is the kind of the row, and the kind that delete_record takes for it. A new budget_deliverable, budget_item or quote_section can include its new children. budget_deliverable_id, budget_item_id and quote_section_id name the parent of a new item, line or quote line. A new budget_deliverable can copy one of the same budget (copy_from_id) or come from from_project_template_deliverable_ids, and then rows lists each new deliverable. After a timeout, read the template with get_proposal_template before you try again.
| Title | Add proposal template row |
| Toolsets | Proposal templates |
| Kind | Writes data |
| Needs | api_create, and update_budgets for budget rows or update_quotes for quote sections and lines |
| Returns | proposal_template_id, row_type, record_kind, row, rows, warnings |
| Input | Type | Required | Description |
|---|---|---|---|
proposal_template_id |
integer | Yes | From search_records with kinds proposal_template. |
row_type |
string | Yes | One of budget_phase, budget_deliverable, budget_item, budget_item_resource, budget_item_cost, quote_section, quote_line, quote_note. |
budget_deliverable_id |
integer | row_type budget_item: its budget deliverable, from get_proposal_template. | |
budget_item_id |
integer | row_type budget_item_resource or budget_item_cost: its budget item, from get_proposal_template. | |
quote_section_id |
integer | row_type quote_line: its section, from get_proposal_template. | |
position |
integer | 1-based place in the row’s list. | |
row |
object | Yes | The keys of row_type, as get_proposal_template shows that row. |
row.name |
string | ||
row.description |
string | ||
row.colour |
string | A phase takes gray, red, orange, yellow, blue, green or indigo. One of red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose, gray. |
|
row.budget_type |
string | One of fixed_price, time_and_materials. |
|
row.budget_phase_id |
integer | A budget phase, from get_proposal_template. | |
row.budget_phase_name |
string | Or a budget phase name. | |
row.kind |
string | fixed: quantity x rate. dynamic: sum of lines. One of fixed, dynamic, non_financial. |
|
row.item_type |
string | One of task, event, process_only. |
|
row.delivery_task_name |
string | Its task name on a project. | |
row.quantity |
number | ||
row.quantity_unit |
string | One of hour, day, per_item. |
|
row.billable_rate_cents |
integer | Tax exclusive. | |
row.resource_type_id |
integer | From search_records with kinds resource_type. | |
row.preferred_member_id |
integer | From search_records with kinds member. | |
row.rate_cents |
integer | Tax exclusive. Omit to use the rate cards. | |
row.notes |
string | ||
row.cost_type_id |
integer | From search_records with kinds cost_type. | |
row.line_item_code_id |
integer | From search_records with kinds line_item_code. | |
row.price_cents |
integer | Tax exclusive. | |
row.finance_account_id |
integer | From search_records with kinds finance_account. | |
row.tax_rate_id |
integer | From search_records with kinds tax_rate. | |
row.content |
string | The text of a note. | |
row.financial |
boolean | true for a financial note. | |
row.items |
array of objects | ||
row.items[].kind |
string | fixed: quantity x rate. dynamic: sum of lines. One of fixed, dynamic, non_financial. |
|
row.items[].name |
string | Yes | |
row.items[].item_type |
string | One of task, event, process_only. |
|
row.items[].description |
string | ||
row.items[].delivery_task_name |
string | Its task name on a project. | |
row.items[].quantity |
number | ||
row.items[].quantity_unit |
string | One of hour, day, per_item. |
|
row.items[].billable_rate_cents |
integer | Tax exclusive. | |
row.items[].resources |
array of objects | ||
row.items[].resources[].resource_type_id |
integer | From search_records with kinds resource_type. | |
row.items[].resources[].preferred_member_id |
integer | From search_records with kinds member. | |
row.items[].resources[].quantity |
number | ||
row.items[].resources[].quantity_unit |
string | One of hour, day, per_item. |
|
row.items[].resources[].rate_cents |
integer | Tax exclusive. Omit to use the rate cards. | |
row.items[].resources[].notes |
string | ||
row.items[].costs |
array of objects | ||
row.items[].costs[].cost_type_id |
integer | Yes | From search_records with kinds cost_type. |
row.items[].costs[].name |
string | Yes | |
row.items[].costs[].description |
string | ||
row.items[].costs[].quantity |
number | ||
row.items[].costs[].quantity_unit |
string | One of hour, day, per_item. |
|
row.items[].costs[].billable_rate_cents |
integer | Tax exclusive. | |
row.resources |
array of objects | ||
row.resources[].resource_type_id |
integer | From search_records with kinds resource_type. | |
row.resources[].preferred_member_id |
integer | From search_records with kinds member. | |
row.resources[].quantity |
number | ||
row.resources[].quantity_unit |
string | One of hour, day, per_item. |
|
row.resources[].rate_cents |
integer | Tax exclusive. Omit to use the rate cards. | |
row.resources[].notes |
string | ||
row.costs |
array of objects | ||
row.costs[].cost_type_id |
integer | Yes | From search_records with kinds cost_type. |
row.costs[].name |
string | Yes | |
row.costs[].description |
string | ||
row.costs[].quantity |
number | ||
row.costs[].quantity_unit |
string | One of hour, day, per_item. |
|
row.costs[].billable_rate_cents |
integer | Tax exclusive. | |
row.lines |
array of objects | ||
row.lines[].line_item_code_id |
integer | From search_records with kinds line_item_code. | |
row.lines[].name |
string | ||
row.lines[].quantity |
number | ||
row.lines[].price_cents |
integer | Tax exclusive. | |
row.lines[].finance_account_id |
integer | From search_records with kinds finance_account. | |
row.lines[].tax_rate_id |
integer | From search_records with kinds tax_rate. | |
row.copy_from_id |
integer | A deliverable of the same budget to copy, from get_proposal_template. | |
row.from_project_template_deliverable_ids |
array of integers | From list_settings_records with kind project_template_deliverable. | |
row.include_quote_sections |
boolean | Only with from_project_template_deliverable_ids. true adds a matched quote section for each new deliverable and keeps the other sections. It needs the quote update permission. A retry adds the rows again. Default false. |
update_proposal_template_row
Change one row of a proposal template by row_type and id (from get_proposal_template). Only the keys sent change, and null clears a field. This tool does not accept child lists: add a child with add_proposal_template_row. budget_deliverable_id moves a budget_item to another budget deliverable, quote_section_id moves a quote line to another section, and position (1 is first) moves the row in its list. A finalised budget refuses a budget row, and delete_record deletes a row with its row_type as kind.
| Title | Update proposal template row |
| Toolsets | Proposal templates |
| Kind | Writes data, Idempotent |
| Needs | api_update, and the same row permission as add_proposal_template_row |
| Returns | proposal_template_id, row_type, record_kind, row, rows, warnings |
| Input | Type | Required | Description |
|---|---|---|---|
proposal_template_id |
integer | Yes | From search_records with kinds proposal_template. |
row_type |
string | Yes | One of budget_phase, budget_deliverable, budget_item, budget_item_resource, budget_item_cost, quote_section, quote_line, quote_note. |
id |
integer | Yes | Row id, from get_proposal_template. |
budget_deliverable_id |
integer | row_type budget_item: move it to this budget deliverable, from get_proposal_template. | |
quote_section_id |
integer | row_type quote_line: move it to this section, from get_proposal_template. | |
position |
integer | 1-based place in the row’s list. | |
row |
object | The keys to change, as get_proposal_template shows that row. | |
row.name |
string | ||
row.description |
string or null | null clears it. | |
row.colour |
string or null | A phase takes gray, red, orange, yellow, blue, green or indigo. null clears it. | |
row.budget_type |
string | One of fixed_price, time_and_materials. |
|
row.budget_phase_id |
integer or null | A budget phase, from get_proposal_template. null clears it. | |
row.budget_phase_name |
string | Or a budget phase name. | |
row.kind |
string | fixed: quantity x rate. dynamic: sum of lines. One of fixed, dynamic, non_financial. |
|
row.item_type |
string | One of task, event, process_only. |
|
row.delivery_task_name |
string or null | Its task name on a project. null clears it. | |
row.quantity |
number | ||
row.quantity_unit |
string | One of hour, day, per_item. |
|
row.billable_rate_cents |
integer | Tax exclusive. | |
row.resource_type_id |
integer | From search_records with kinds resource_type. | |
row.preferred_member_id |
integer or null | From search_records with kinds member. null clears it. | |
row.rate_cents |
integer | Tax exclusive. Omit to use the rate cards. | |
row.notes |
string or null | null clears it. | |
row.cost_type_id |
integer | From search_records with kinds cost_type. | |
row.line_item_code_id |
integer or null | From search_records with kinds line_item_code. null clears it. | |
row.price_cents |
integer | Tax exclusive. | |
row.finance_account_id |
integer or null | From search_records with kinds finance_account. null clears it. | |
row.tax_rate_id |
integer or null | From search_records with kinds tax_rate. null clears it. | |
row.content |
string | The text of a note. | |
row.financial |
boolean | true for a financial note. |
change_proposal_template_budget_structure
Rebuild the budget of a proposal template from a project template or another proposal template. All deliverables of the budget are removed first, so changes to them are lost. The phases of a project template merge into the budget phases by name, and the phases of a proposal template replace them. Without template_id, the budget is rebuilt from the project template of the proposal template. It needs the API update and delete permissions. Ask the user before you call this tool.
| Title | Change proposal template budget structure |
| Toolsets | Proposal templates |
| Kind | Writes data, Destructive |
| Needs | api_update, api_delete and update_budgets |
| Returns | id, name, description, project_template, currency, default_sent_days, default_expiry_days, template_document, deleted, budget, note_count, note_ids, quote_section_count, quote_sections, warnings |
| Input | Type | Required | Description |
|---|---|---|---|
proposal_template_id |
integer | Yes | From search_records with kinds proposal_template. |
template_type |
string | Yes | The kind of template_id. One of project_template, proposal_template. |
template_id |
integer | From search_records with kinds project_template (not a baseline) or proposal_template. |
sync_proposal_template_budget_to_quote
Rebuild the quote sections and lines of a proposal template from its budget, as the Sync Budget screen does. All sections are replaced, so text written in them is lost. Ask the user before you call this tool.
| Title | Sync proposal template budget to quote |
| Toolsets | Proposal templates |
| Kind | Writes data, Destructive |
| Needs | api_update, api_delete, and the permission to sync the budget to the quote |
| Returns | id, name, description, project_template, currency, default_sent_days, default_expiry_days, template_document, deleted, budget, note_count, note_ids, quote_section_count, quote_sections, warnings |
| Input | Type | Required | Description |
|---|---|---|---|
proposal_template_id |
integer | Yes | From search_records with kinds proposal_template. |
method |
string | Yes | matched: a section per deliverable, a line per item. multiple_stages: a section per deliverable, one total line. single_stage: one section, a line per deliverable. One of matched, single_stage, multiple_stages. |
include_non_budgeted |
boolean | Also add items with no budget value. Default false. |
sync_proposal_template_deliverable
Rebuild one budget deliverable of a proposal template from its project template deliverable, as “Sync from template” on the budget page does. The user’s changes to that deliverable (name, items, lines and typed rates) are lost, and items the template does not have are deleted. Drum already syncs the deliverables that the user did not change, so use this for a template_status of customised_template_changed, after the user agrees. Ask the user before you call this tool.
| Title | Sync proposal template deliverable |
| Toolsets | Proposal templates |
| Kind | Writes data, Destructive |
| Needs | api_update, api_delete and update_budgets |
| Returns | proposal_template_id, row_type, record_kind, row, rows, warnings |
| Input | Type | Required | Description |
|---|---|---|---|
proposal_template_id |
integer | Yes | From search_records with kinds proposal_template. |
budget_deliverable_id |
integer | Yes | A budget deliverable of that proposal template, from get_proposal_template. |
apply_proposal_template_current_rates
Give one budget deliverable of a proposal template the rate card’s current rates, as “Apply current rates” on the budget page does. It changes the resource lines in its out_of_date_rates (rates that the rate card set and has since changed) and their totals. Typed rates and every other change stay. A new proposal copies a template’s rates, so apply them before the template is used. The warning rates_unchanged says that no rate was out of date.
| Title | Apply proposal template current rates |
| Toolsets | Proposal templates |
| Kind | Writes data, Idempotent |
| Needs | api_update and update_budgets |
| Returns | proposal_template_id, row_type, record_kind, row, rows, warnings |
| Input | Type | Required | Description |
|---|---|---|---|
proposal_template_id |
integer | Yes | From search_records with kinds proposal_template. |
budget_deliverable_id |
integer | Yes | A budget deliverable of that proposal template, from get_proposal_template. |
save_proposal_template_rate_card
Create or update the custom rate card of one proposal template, as the proposal settings screen does. Send no id to make a new custom card that the template uses, or its id to update it. Omit a field to keep it, and send null to clear it. After a timeout, read the template with get_proposal_template before you try again. entries are role rates (resource_type) and member rates (member), and entries left out are kept. Existing budget lines keep their rates (apply_proposal_template_rate_card_rates changes them), and delete_record deletes an entry (kind rate_card_entry) or the card.
| Title | Save proposal template rate card |
| Toolsets | Proposal templates |
| Kind | Writes data |
| Needs | api_create for a new card or api_update, and update_budgets |
| Returns | proposal_template_id, proposal_budget_id, account_rate_card, rate_card, rate_cards, warnings |
| Input | Type | Required | Description |
|---|---|---|---|
proposal_template_id |
integer | Yes | From search_records with kinds proposal_template. |
id |
integer | The card to update, from list_settings_records with kind proposal_template_rate_card. Omit to create. | |
name |
string | Required when creating. | |
description |
string or null | null clears it. | |
entries |
array of objects | Role and member rates. Entries left out are kept. | |
entries[].id |
integer | An entry of the card, from list_settings_records. Omit to add or match by rateable. | |
entries[].rateable_type |
string | resource_type for a role rate, member for a member rate. Required for a new entry. One of resource_type, member. |
|
entries[].rateable_id |
integer | From search_records with kinds resource_type or member. Required for a new entry. | |
entries[].billable_rate_cents |
integer | The hourly rate in cents, tax exclusive. 0 is refused unless allow_zero_value. | |
entries[].allow_zero_value |
boolean | Keep a zero rate. |
apply_proposal_template_rate_card_rates
Put the rates of the custom rate card of a proposal template on every existing resource line of its budget, as the Apply below rates box of the rate card form does. Manual rates are replaced too, and this cannot be reversed. The warning rates_applied_to_existing gives the number of lines changed. Ask the user before you call this tool.
| Title | Apply proposal template rate card rates |
| Toolsets | Proposal templates |
| Kind | Writes data, Destructive, Idempotent |
| Needs | api_update and update_budgets |
| Returns | proposal_template_id, proposal_budget_id, account_rate_card, rate_card, rate_cards, warnings |
| Input | Type | Required | Description |
|---|---|---|---|
proposal_template_id |
integer | Yes | From search_records with kinds proposal_template. |