Beta
This API is in beta. Endpoints and response shapes may change as we iterate. For questions or feedback, email support@smartpricingtable.com.
Include your API key in the Authorization header:
You can create and manage API keys from your profile settings.
List endpoints return paginated results. Include page and limit query parameters to control which page of results you receive.
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | integer | 1 | Page number (starts at 1) |
| limit | integer | 20 | Items per page (1–100) |
Every list response includes a pagination object alongside the data array:
{
"data": [ ... ],
"pagination": {
"page": 1,
"limit": 20,
"total": 150,
"pages": 8
}
}Retrieve a paginated list of proposals for the authenticated user's organization. Templates are excluded by default. Pass `is_template=true` to list reusable templates instead of regular proposals (not both). Use a returned template's `id` with `POST /api/proposals` (`templateId`) to create a proposal from that template.
falsedefaulttrueanydescdefaultasccreated_atdefaultupdated_atnamestatusclient_namesentexpiring_oncompletedlast_activitydraftsentwonlostcancelled{
"data": []
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Create a new proposal for the user's organization. To start from a template, first call GET /api/proposals?is_template=true and copy the template id. Then POST that id as templateId, along with name and the client under settings.recipient. The new proposal is a copy of the template. Pages, pricing, and design come from the template. settings.recipient replaces the template's client. settings.recipient.name is the company name. settings.recipient.contact.name, contact.email, and contact.phone are the person. address and website are optional. Only the settings keys you send replace the template; everything else stays. Omit templateId to create a blank proposal. Set is_template to true to create a reusable template instead of a proposal. A default send email saved on your template is copied onto the new proposal as settings.template_send_email (subject and message, no signature). Send that email with POST /api/proposals/{id}/send-email. To link the new proposal to a CRM record, pass integrations.crm.provider and integrations.crm.deal_id. provider is hubspot, pipedrive, zoho, or gohighlevel. deal_id is that record's id in the CRM (a HubSpot, Pipedrive, or Zoho deal, or a Go High Level opportunity). The organization must already have that CRM connected. The record is looked up and linked. Name matching is not used. Recipient fields are not copied from the CRM; send settings.recipient when the client should be filled in. The proposal URL is written to the field configured in Integrations, and the proposal total syncs to the deal value. When the account has Add tax from CRM turned on, a HubSpot deal's tax rate is written onto the new proposal's pricing pages. salesTaxPercentage on this request wins over that rate.
{
"name": "Acme website redesign",
"templateId": "zw5FD5HGcfE3",
"settings": {
"recipient": {
"name": "Acme Co",
"address": "123 Main St, Tulsa, OK",
"website": "https://acme.example",
"contact": {
"name": "Jane Smith",
"email": "jane@acme.example",
"phone": "555-0100"
}
}
}
}{
"data": {
"id": "example-string"
}
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Retrieve detailed information about a specific proposal including all items and groups. For an importable backup matching More → Export as JSON in the app, use GET /api/proposals/{id}/export instead.
null{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "NOT_FOUND",
"message": "Proposal not found"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Update proposal details such as name, description, or client information
nullnull{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Delete a proposal and all its associated items. The proposal will no longer appear in listings.
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "NOT_FOUND",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Retrieve analytics events for a specific proposal. Requires authentication and membership in the proposal's organization (or platform admin).
proposal_viewedproposal_sentstatus_changedproposal_signedpdf_viewedsignature_request_sent{
"data": [
{
"event_timestamp": "2024-01-20T15:30:00Z",
"event_type": "example-string",
"id": "example-string",
"metadata": {},
"user": {
"email": "example-string",
"full_name": "example-string",
"public_id": "example-string"
}
}
]
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Archive a proposal by setting its archived_at timestamp. Archived proposals are excluded from default listings and become read-only.
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": "Not authorized to archive this proposal"
}{
"error": "Proposal not found"
}{
"error": "Proposal is already archived"
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Archive multiple items (line items, groups) from a proposal
{
"itemIds": [
"abcdefgh1234",
"ijklmnop5678"
]
}{
"archivedCount": 3,
"errors": [
"example-string"
],
"message": "Successfully archived 3 items"
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Create a complete copy of an existing proposal with all its groups, items, and pages
{
"name": "Copy of Q1 2024 Proposal"
}{
"data": {
"id": "example-string"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Download a proposal or template as the same importable JSON file produced by More → Export as JSON in the app. Save the response body and import it with Create Proposal → Import from JSON — no transformation needed. The response is the export object itself (not wrapped in a data envelope). Non-portable fields such as signature state, payment sessions, and email drafts are stripped, and status is set to DRAFT, matching the in-app export.
{
"name": "example-string",
"pages": [
{}
],
"design": {},
"id": "example-string",
"is_template": true,
"settings": {},
"status": "DRAFT"
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "NOT_FOUND",
"message": "example-string"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Create a brand-new line item, group, or side-by-side directly inside a proposal (not copied from the library). A line item is added to a group (target_group_id, or the first group by default); a group or side-by-side is added under a Scope of Work page (scope_of_work_page_id, or the first one by default). Pass after_item_id / before_item_id to position the new item relative to an existing one — it then inherits that item's parent. To create a side-by-side on a proposal, send type=side_by_side with a non-empty columns array. To save one in the library instead, POST /api/library/side-by-sides. Each column price is a number in dollars (default 0). Side-by-sides have no URL of their own; to change one later, PATCH /api/items/{id} with an { "item": { ... } } body. Prices are in dollars (major currency units), not cents. Color theme: set theme to a built-in id (metals, ocean, forest, sunset, monochrome, pastel, neon, earth, berry, corporate) or design for a custom theme. theme paints column colors (cycled), the container, and — when style is comparison — the features column and headings. design.container, design.featuresColumn, design.heading, and design.columns (a cycled palette) are the custom settings. A design object on an individual column overrides that column. Send design with theme to start from a built-in theme and override pieces of it.
line_itemgroupside_by_sidesinglemultipleloosestandardcomparisonmetalsoceanforestsunsetmonochromepastelneonearthberrycorporate{
"name": "example-string",
"type": "line_item",
"after_item_id": "example-string",
"before_item_id": "example-string",
"columns": [
{
"name": "example-string",
"description": "example-string",
"design": {
"background": "example-string",
"borderColor": "example-string",
"borderRadius": 100,
"borderWidth": 100,
"buttonColor": "example-string",
"buttonTextColor": "example-string",
"checkmarkColor": "example-string",
"fontColor": "example-string",
"priceColor": "example-string",
"quantityBackgroundColor": "example-string",
"quantityFontColor": "example-string",
"titleColor": "example-string"
},
"feeType": "fixed",
"frequency": "example-string",
"includedFeatures": [
"example-string"
],
"isSelected": true,
"price": 499
}
],
"description": "example-string",
"design": {
"columns": [
{}
],
"container": {
"background": "example-string",
"borderColor": "example-string",
"borderWidth": 100,
"fontColor": "example-string",
"selectionOutlineColor": "example-string",
"showHeader": true,
"sizeModifier": "compact"
},
"featuresColumn": {
"background": "example-string",
"borderColor": "example-string",
"borderRadius": 100,
"borderWidth": 100,
"fontColor": "example-string"
},
"heading": {
"alignment": "left",
"background": "example-string",
"fontColor": "example-string"
}
},
"features": [
{
"name": "example-string",
"order_key": 100
}
],
"optional": true,
"order_key": 100,
"price": {
"frequency": "once",
"model": "fixed",
"quantity": {
"current": 100,
"max": 100,
"min": 100,
"unitLabel": "example-string"
},
"value": 379
},
"scope_of_work_page_id": "example-string",
"selected": true,
"selection_type": "single",
"style": "standard",
"tags": [
"example-string"
],
"target_group_id": "example-string",
"theme": "metals"
}{
"data": {
"id": "example-string",
"name": "example-string",
"order_key": 100,
"type": "example-string"
},
"success": true
}Copies a saved library item (line item, group, page, or side-by-side) into the specified proposal. The library item and the target proposal must belong to the same organization. The copy is always a deep, autonomous copy — it does not stay linked to or synced with the library source. Library content is never modified by this operation.
line_itemgrouppageside_by_side{
"library_item_id": "example-string",
"type": "line_item",
"after_item_id": "example-string",
"before_item_id": "example-string",
"order_key": 100,
"scope_of_work_page_id": "example-string",
"target_group_id": "example-string"
}{
"data": {
"id": "example-string",
"name": "example-string",
"order_key": 100,
"type": "example-string"
},
"success": true
}Generate a PDF document for the specified proposal. Returns the PDF as a binary download.
{}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Email the proposal to one or more recipients and mark it Sent. This is the same action as Send in the app. Authenticate with a Bearer API key. The key's user must be allowed to send proposals. recipients, subject, message, and fromEmail are required. recipients is an array of { name, email }, or a comma-separated list of email addresses. fromEmail is the address shown as the sender. To send the email saved on a template: create the proposal with templateId (see Create Proposal). The template's subject and message are copied onto the new proposal as settings.template_send_email. GET the proposal, then pass those values as subject and message here, along with the client's email. The saved email signature of the API key's user is appended to message. Pass signature_user_id (a public user id belonging to this organization) to use that member's signature instead. If that person has no signature, the email still sends without one. Pass include_signature false to send message exactly as given. These tokens in subject and message are replaced for each recipient: [recipient_contact_full_name], [recipient_contact_first_name], [recipient_contact_email_address], [recipient_company_name], [recipient_address], [recipient_website], [proposal_creator_full_name], [proposal_creator_email_address], [proposal_creator_phone_number], and [view_proposal_button label="View Proposal"].
{
"recipients": [
{
"name": "Jane Smith",
"email": "jane@acme.example"
}
],
"subject": "Proposal for Acme Co",
"message": "<p>Hi [recipient_contact_first_name], your proposal is ready.</p>",
"fromEmail": "eddie@yourcompany.example"
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Star a proposal for the current user. Starred proposals appear first in listings. This operation is idempotent - starring an already-starred proposal has no effect.
{
"is_starred": true
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "NOT_FOUND",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Unarchive a proposal by clearing its archived_at timestamp. The proposal will return to active status and become editable again.
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": "Not authorized to unarchive this proposal"
}{
"error": "Proposal not found"
}{
"error": "Proposal is not archived"
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Remove the star from a proposal for the current user. This operation is idempotent - unstarring a proposal that is not starred has no effect.
{
"is_starred": false
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "NOT_FOUND",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Archive more than one library entry in one call. itemIds are Public IDs returned by the API (for example zw5FD5HGcfE3), not the editor Item ID field (externalItemId). Each id must belong to your organization's library. Line items, groups, and pages are accepted. Archiving hides an entry so it can be restored; it is not a permanent delete. Up to 2000 ids per request. Requires the Manage Library permission. A partial failure still returns 200: archivedCount is how many succeeded, and errors lists the rest.
{
"itemIds": [
"zw5FD5HGcfE3",
"kP3mNq8rT2xY"
]
}{
"archivedCount": 3,
"errors": [
"example-string"
],
"message": "Successfully archived 3 items"
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Add a page to a proposal (parent_proposal, the proposal's Public ID) or to your organization's library (in_library true). Send exactly one of the two. The page's fields go inside "page"; only page.name (the title) is required, and page.content is the HTML body. The new page is added at the end unless you send page.order_key. Example: { "parent_proposal": "zw5FD5HGcfE3", "page": { "name": "About Us", "content": "<p>We have served clients since 2010.</p>" } }. Set page.hideSection true to create the page hidden from recipients (the editor "Hide this Page" toggle). Staff still see it; recipients do not. Hidden Scope of Work pages are left out of grand totals. This is not the same as archiving the page. Set page.excludeFromPdf true to leave the page out of PDF exports only. Set page.isScopeOfWork true to create a Scope of Work (pricing) page. It starts empty and uses your organization's pricing-table defaults. Add groups, line items, and side-by-sides to it with POST /api/proposals/{id}/items (scope_of_work_page_id set to the returned id). Proposals that are pending signature, won, or lost cannot be edited (409).
{
"page": {
"name": "example-string",
"children": [
{
"displayCost": "show_all",
"id": "example-string",
"isOptional": true,
"isSelected": true,
"kind": "group",
"lineItems": [
{
"children": [],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [],
"terms": "example-string",
"updated_at": "example-string"
}
],
"name": "example-string",
"selectionType": "single",
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"hidden": true,
"hideQuantities": true,
"in_library": true,
"internalNotes": "example-string",
"is_archived": true,
"linkedScopeId": "example-string",
"locked": true,
"order_key": 100,
"pdfPageBreak": true,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": []
},
"requireSelection": true,
"startExpanded": true,
"tags": [
"example-string"
],
"updated_at": "example-string"
}
],
"content": "example-string",
"designSettings": {
"backgroundAttachment": "example-string",
"backgroundColor": "example-string",
"backgroundImage": "example-string",
"backgroundOpacity": 100,
"backgroundPosition": "example-string",
"backgroundRepeat": "example-string",
"backgroundSize": "example-string",
"contentAlign": "left",
"contentWidth": "full",
"fontColor": "example-string"
},
"discounts": [
{
"amount": "example-string",
"frequency": "example-string",
"id": "example-string",
"type": "fixed"
}
],
"displayHeading": true,
"excludeFromPdf": true,
"hideSection": true,
"hideTotalsBottom": true,
"hideTotalsTop": true,
"isScopeOfWork": true,
"isSignaturesPage": true,
"kind": "example-string",
"labels": {
"outOfPocket": "example-string",
"tax": "example-string"
},
"lineItemsStartExpanded": "none",
"markupPercentage": "example-string",
"order_key": 100,
"requireSelection": true,
"salesTaxPercentage": "example-string",
"scopeId": "example-string",
"screenshotUrl": "example-string",
"selectionType": "single",
"showCents": true,
"startNewPdfPage": true,
"tags": [
"example-string"
],
"useRoundedAmounts": true
},
"in_library": true,
"parent_proposal": "zw5FD5HGcfE3"
}noneallfirstsinglemultipleloose{
"data": {
"content": "example-string",
"name": "example-string",
"order_key": 100,
"children": [
{
"displayCost": "show_all",
"id": "example-string",
"isOptional": true,
"isSelected": true,
"kind": "group",
"lineItems": [
{
"children": [],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [],
"terms": "example-string",
"updated_at": "example-string"
}
],
"name": "example-string",
"selectionType": "single",
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"hidden": true,
"hideQuantities": true,
"in_library": true,
"internalNotes": "example-string",
"is_archived": true,
"linkedScopeId": "example-string",
"locked": true,
"order_key": 100,
"pdfPageBreak": true,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": []
},
"requireSelection": true,
"startExpanded": true,
"tags": [
"example-string"
],
"updated_at": "example-string"
}
],
"created_at": "example-string",
"designSettings": {
"backgroundAttachment": "example-string",
"backgroundColor": "example-string",
"backgroundImage": "example-string",
"backgroundOpacity": 100,
"backgroundPosition": "example-string",
"backgroundRepeat": "example-string",
"backgroundSize": "example-string",
"contentAlign": "left",
"contentWidth": "full",
"fontColor": "example-string"
},
"discounts": [
{
"amount": "example-string",
"frequency": "example-string",
"id": "example-string",
"type": "fixed"
}
],
"displayHeading": true,
"excludeFromPdf": true,
"hideSection": true,
"hideTotalsBottom": true,
"hideTotalsTop": true,
"id": "example-string",
"isScopeOfWork": true,
"isSignaturesPage": true,
"kind": "example-string",
"labels": {
"outOfPocket": "example-string",
"tax": "example-string"
},
"lineItemsStartExpanded": "none",
"markupPercentage": "example-string",
"requireSelection": true,
"salesTaxPercentage": "example-string",
"scopeId": "example-string",
"screenshotUrl": "example-string",
"selectionType": "single",
"showCents": true,
"startNewPdfPage": true,
"tags": [
"example-string"
],
"updated_at": "example-string",
"useRoundedAmounts": true
}
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Return one page with its title (name), HTML body (content), and settings. hideSection is true when the page is hidden from recipients (the editor "Hide this Page" toggle). isScopeOfWork is true for a pricing page. The groups and side-by-sides on a Scope of Work page are not included; read them with ListGroups or GetProposal. The page object is returned at the top level, with no "data" wrapper.
noneallfirstsinglemultipleloose{
"content": "example-string",
"name": "example-string",
"order_key": 100,
"children": [
{
"displayCost": "show_all",
"id": "example-string",
"isOptional": true,
"isSelected": true,
"kind": "group",
"lineItems": [
{
"children": [],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {}
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
],
"name": "example-string",
"selectionType": "single",
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"hidden": true,
"hideQuantities": true,
"in_library": true,
"internalNotes": "example-string",
"is_archived": true,
"linkedScopeId": "example-string",
"locked": true,
"order_key": 100,
"pdfPageBreak": true,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{}
]
},
"requireSelection": true,
"startExpanded": true,
"tags": [
"example-string"
],
"updated_at": "example-string"
}
],
"created_at": "example-string",
"designSettings": {
"backgroundAttachment": "example-string",
"backgroundColor": "example-string",
"backgroundImage": "example-string",
"backgroundOpacity": 100,
"backgroundPosition": "example-string",
"backgroundRepeat": "example-string",
"backgroundSize": "example-string",
"contentAlign": "left",
"contentWidth": "full",
"fontColor": "example-string"
},
"discounts": [
{
"amount": "example-string",
"frequency": "example-string",
"id": "example-string",
"type": "fixed"
}
],
"displayHeading": true,
"excludeFromPdf": true,
"hideSection": true,
"hideTotalsBottom": true,
"hideTotalsTop": true,
"id": "example-string",
"isScopeOfWork": true,
"isSignaturesPage": true,
"kind": "example-string",
"labels": {
"outOfPocket": "example-string",
"tax": "example-string"
},
"lineItemsStartExpanded": "none",
"markupPercentage": "example-string",
"requireSelection": true,
"salesTaxPercentage": "example-string",
"scopeId": "example-string",
"screenshotUrl": "example-string",
"selectionType": "single",
"showCents": true,
"startNewPdfPage": true,
"tags": [
"example-string"
],
"updated_at": "example-string",
"useRoundedAmounts": true
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Change a page's title, HTML body, or settings. Only the fields you send change. The body is flat, with no "page" wrapper. name is the page title and content is the HTML body. Example: { "name": "Our Approach", "content": "<p>We start with discovery.</p>" }. To hide a page from recipients (the editor "Hide this Page" toggle), send hideSection: true. Staff still see the page in the editor; recipients do not, and hidden Scope of Work pages are left out of grand totals. This is not ArchivePage. Send hideSection: false to show the page again. excludeFromPdf only affects PDF exports. On a Scope of Work page you can also change pricing-table settings such as selectionType, requireSelection, showCents, useRoundedAmounts, hideTotalsTop, hideTotalsBottom, salesTaxPercentage, markupPercentage, and discounts. Groups, side-by-sides, and line items on the page are not edited here; children in the body is ignored. Use UpdateGroup, UpdateItem, and UpdateModification for those. To change a line item's price, use PATCH /api/items/{id}. Proposals that are pending signature, won, or lost cannot be edited (409 PROPOSAL_LOCKED), and neither can a locked customer version.
noneallfirstsinglemultipleloose{
"children": [
{
"displayCost": "show_all",
"id": "example-string",
"isOptional": true,
"isSelected": true,
"kind": "group",
"lineItems": [
{
"children": [],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {}
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
],
"name": "example-string",
"selectionType": "single",
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"hidden": true,
"hideQuantities": true,
"in_library": true,
"internalNotes": "example-string",
"is_archived": true,
"linkedScopeId": "example-string",
"locked": true,
"order_key": 100,
"pdfPageBreak": true,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{}
]
},
"requireSelection": true,
"startExpanded": true,
"tags": [
"example-string"
],
"updated_at": "example-string"
}
],
"content": "example-string",
"designSettings": {
"backgroundAttachment": "example-string",
"backgroundColor": "example-string",
"backgroundImage": "example-string",
"backgroundOpacity": 100,
"backgroundPosition": "example-string",
"backgroundRepeat": "example-string",
"backgroundSize": "example-string",
"contentAlign": "left",
"contentWidth": "full",
"fontColor": "example-string"
},
"discounts": [
{
"amount": "example-string",
"frequency": "example-string",
"id": "example-string",
"type": "fixed"
}
],
"displayHeading": true,
"excludeFromPdf": true,
"hideSection": true,
"hideTotalsBottom": true,
"hideTotalsTop": true,
"isScopeOfWork": true,
"isSignaturesPage": true,
"kind": "example-string",
"labels": {
"outOfPocket": "example-string",
"tax": "example-string"
},
"lineItemsStartExpanded": "none",
"markupPercentage": "example-string",
"name": "example-string",
"order_key": 100,
"requireSelection": true,
"salesTaxPercentage": "example-string",
"scopeId": "example-string",
"screenshotUrl": "example-string",
"selectionType": "single",
"showCents": true,
"startNewPdfPage": true,
"tags": [
"example-string"
],
"useRoundedAmounts": true
}{
"data": {
"attrs": {},
"created_at": "2024-01-20T15:30:00Z",
"id": "zw5FD5HGcfE3",
"kind": "page",
"name": "example-string",
"order_key": 100,
"proposal_id": "example-string",
"updated_at": "2024-01-20T15:30:00Z"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "DUPLICATE_NAME",
"existingPageId": "example-string",
"message": "A page with the name \"Page Name\" already exists in the library."
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Delete a page. It is soft-deleted: it disappears from the proposal and from API responses. Deleting a Scope of Work page also deletes its groups, side-by-sides, and line items. To remove a page but keep the option to bring it back, use ArchivePage and UnarchivePage instead. Requires permission to delete proposals.
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Remove a page from the proposal in a way you can undo. The archived page is hidden from the proposal and left out of default list responses. Archiving a Scope of Work page recalculates the proposal totals. Bring it back with UnarchivePage. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Copy a page. With an empty body, the copy is placed directly below the original in the same proposal and named "Copy of <original name>". For a Scope of Work page this is a deep copy: its groups, line items, modifications, and side-by-sides are copied too. Other modes, chosen by the body: toLibrary=true saves the page to the content library (with optional tags). toProposal (a proposal Public ID) adds a library page to that proposal; add fromProposal=true to copy a page from another proposal instead (signature pages cannot be copied this way). toPage (a page Public ID) overwrites that page with this page's content. Proposals that are pending signature, won, or lost cannot be edited (409). Copying from another proposal into one of those proposals returns 400.
{
"attrs": {},
"fromProposal": true,
"name": "Terms and Conditions (2026)",
"order_key": 100,
"sourceOrgId": "example-string",
"sourceProposalName": "example-string",
"tags": [
"example-string"
],
"toLibrary": true,
"toPage": "example-string",
"toProposal": "zw5FD5HGcfE3"
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Change a page's position in its proposal. Send after_id as the Public ID of the page it should follow, or null (or the proposal's Public ID) to move it to the top. You can send order_key instead to set an exact position. The page's content and, for a Scope of Work page, its pricing move with it. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"after_id": "zw5FD5HGcfE3",
"order_key": 3
}{
"data": {
"id": "zw5FD5HGcfE3",
"order_key": 100
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Restore an archived page so it shows in the proposal again. For a Scope of Work page, its groups, side-by-sides, and line items are restored too, and the proposal totals are recalculated. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Return a proposal's pages in order, with each page's Public ID, title (name), HTML body (content), and settings. isScopeOfWork is true for pricing pages. Use a returned id with GetPage, UpdatePage, or as scope_of_work_page_id when adding groups and side-by-sides.
ascdefaultdescorder_keydefaultnamecreated_atupdated_atnoneallfirstsinglemultipleloose{
"data": [
{
"content": "example-string",
"name": "example-string",
"order_key": 100,
"children": [
{
"displayCost": "show_all",
"id": "example-string",
"isOptional": true,
"isSelected": true,
"kind": "group",
"lineItems": [
{}
],
"name": "example-string",
"selectionType": "single",
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"hidden": true,
"hideQuantities": true,
"in_library": true,
"internalNotes": "example-string",
"is_archived": true,
"linkedScopeId": "example-string",
"locked": true,
"order_key": 100,
"pdfPageBreak": true,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"requireSelection": true,
"startExpanded": true,
"tags": [
"example-string"
],
"updated_at": "example-string"
}
],
"created_at": "example-string",
"designSettings": {
"backgroundAttachment": "example-string",
"backgroundColor": "example-string",
"backgroundImage": "example-string",
"backgroundOpacity": 100,
"backgroundPosition": "example-string",
"backgroundRepeat": "example-string",
"backgroundSize": "example-string",
"contentAlign": "left",
"contentWidth": "full",
"fontColor": "example-string"
},
"discounts": [
{
"amount": "example-string",
"frequency": "example-string",
"id": "example-string",
"type": "fixed"
}
],
"displayHeading": true,
"excludeFromPdf": true,
"hideSection": true,
"hideTotalsBottom": true,
"hideTotalsTop": true,
"id": "example-string",
"isScopeOfWork": true,
"isSignaturesPage": true,
"kind": "example-string",
"labels": {
"outOfPocket": "example-string",
"tax": "example-string"
},
"lineItemsStartExpanded": "none",
"markupPercentage": "example-string",
"requireSelection": true,
"salesTaxPercentage": "example-string",
"scopeId": "example-string",
"screenshotUrl": "example-string",
"selectionType": "single",
"showCents": true,
"startNewPdfPage": true,
"tags": [
"example-string"
],
"updated_at": "example-string",
"useRoundedAmounts": true
}
],
"pagination": {}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Set the order of a proposal's pages. Send page_ids as the Public IDs of the pages in the order you want; the first id is shown first. Include every page. Pages you leave out are placed after the listed pages, sorted alphabetically by name. Every id must be a page in this proposal, otherwise the request fails with 400. To move one page, use MovePage. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"page_ids": [
"qeP5CKvwBveC",
"N66wN1Yhese9",
"Vv5EYHv5aNEx"
]
}{
"message": "Pages reordered successfully",
"updated_pages": [
{
"id": "example-string",
"name": "example-string",
"order_key": 100
}
]
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Create an empty group (a set of line items shown together in a pricing table). Send exactly one parent: - parent_proposal: Public ID of a proposal. The group goes on the proposal's first Scope of Work page. - parent_page: Public ID of a Scope of Work page. - in_library: true saves the group to your organization's library. The group's fields go inside "group"; only group.name is required. The new group is added at the end of the page. Example: { "parent_proposal": "zw5FD5HGcfE3", "group": { "name": "Phase 1", "isOptional": false } }. A group has no price of its own. Add line items with CreateItem (parent_group set to the returned id) or with POST /api/proposals/{id}/items (type line_item, target_group_id). To place a group next to an existing one, POST /api/proposals/{id}/items with type group is usually simpler. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"group": {
"name": "example-string",
"description": "example-string",
"displayCost": "show_all",
"hidden": true,
"hideQuantities": true,
"in_library": true,
"internalNotes": "example-string",
"isOptional": true,
"isSelected": true,
"kind": "group",
"locked": true,
"order_key": 100,
"pdfPageBreak": true,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{
"unitPrice": 100,
"upTo": 100
}
]
},
"requireSelection": true,
"selectionType": "single",
"startExpanded": true,
"tags": [
"example-string"
]
},
"in_library": true,
"parent_page": "example-string",
"parent_proposal": "zw5FD5HGcfE3"
}{
"data": {
"id": "zw5FD5HGcfE3",
"kind": "group",
"name": "example-string",
"parent_id": "example-string"
}
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Return one group with its settings and its line items. Each line item includes its Public ID, its price, and its modifications (children). For fixed prices, price.value is in dollars, not cents. Use the line item and modification ids with UpdateItem and UpdateModification to change prices.
show_allhide_allhide_item_costshide_group_costsinglemultipleloose{
"data": {
"displayCost": "show_all",
"id": "example-string",
"isOptional": true,
"isSelected": true,
"lineItems": [
{
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {}
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
],
"name": "example-string",
"selectionType": "single",
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"hidden": true,
"hideQuantities": true,
"in_library": true,
"internalNotes": "example-string",
"is_archived": true,
"kind": "group",
"linkedScopeId": "example-string",
"locked": true,
"order_key": 100,
"pdfPageBreak": true,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{
"unitPrice": 100,
"upTo": 100
}
]
},
"requireSelection": true,
"startExpanded": true,
"tags": [
"example-string"
],
"updated_at": "example-string"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Change a group's name, description, or settings. Only the fields you send change. The body is flat, with no "group" wrapper. Example: { "name": "Phase 2", "isOptional": true, "selectionType": "single" }. A group has no price of its own; its total comes from its line items. To change a line item's price, use UpdateItem (PATCH /api/items/{id}). quantity sets a group-level multiplier applied to the group's line items. Proposals that are pending signature, won, or lost cannot be edited (409 PROPOSAL_LOCKED), and neither can a locked customer version.
show_allhide_allhide_item_costshide_group_costsinglemultipleloose{
"description": "example-string",
"displayCost": "show_all",
"hidden": true,
"hideQuantities": true,
"in_library": true,
"internalNotes": "example-string",
"isOptional": true,
"isSelected": true,
"kind": "group",
"locked": true,
"name": "example-string",
"order_key": 100,
"pdfPageBreak": true,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{
"unitPrice": 100,
"upTo": 100
}
]
},
"requireSelection": true,
"selectionType": "single",
"startExpanded": true,
"tags": [
"example-string"
]
}{
"data": {
"attrs": {},
"created_at": "2024-01-20T15:30:00Z",
"id": "zw5FD5HGcfE3",
"kind": "group",
"name": "example-string",
"optional": true,
"order_key": 100,
"selected": true,
"updated_at": "2024-01-20T15:30:00Z"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "DUPLICATE_NAME",
"existingGroupId": "example-string",
"message": "A group with the name \"Group Name\" already exists in the library."
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Delete a group and every line item in it. They are soft-deleted: they disappear from the proposal and from API responses, and the proposal totals are recalculated. To remove a group but keep the option to bring it back, use ArchiveGroup and UnarchiveGroup instead. Requires permission to delete proposals.
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Remove a group from the proposal in a way you can undo. The archived group, and the line items shown inside it, are hidden from the proposal and left out of default list responses. Bring it back with UnarchiveGroup. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Copy a group with its settings, line items, and their modifications. Prices are copied as they are. With an empty body the copy goes on the same Scope of Work page, named "<original name> - Copy". To copy into another proposal, send proposalId (Public ID of the destination proposal) and parent_item_id (Public ID of a Scope of Work page in that proposal). A copy into another proposal keeps the original name unless you send name. The destination cannot be pending signature, won, or lost. Other modes: toLibrary true saves the group to your library, and toGroup overwrites an existing group with this group's content.
singlemultipleloose{
"includeItems": true,
"name": "Website Development - Copy",
"orderKey": 1.5,
"parent_item_id": "example-string",
"proposalId": "example-string",
"selectionType": "single",
"tags": [
"example-string"
],
"toGroup": "example-string",
"toLibrary": true
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Change a group's position on its Scope of Work page. Set after_id to the Public ID of another group on the same page to place this group right after it, or to the Public ID of the proposal to place it first. The group stays on its current page, and its line items move with it. To set the order of many groups at once, use ReorderProposalGroups. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"after_id": "ijklmnop5678"
}{
"data": {
"id": "zw5FD5HGcfE3"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Restore an archived group so it shows in the proposal again, with its line items and settings. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Archive more than one library entry in one call. itemIds are Public IDs returned by the API (for example zw5FD5HGcfE3), not the editor Item ID field (externalItemId). Each id must belong to your organization's library. Line items, groups, and pages are accepted. Archiving hides an entry so it can be restored; it is not a permanent delete. Up to 2000 ids per request. Requires the Manage Library permission. A partial failure still returns 200: archivedCount is how many succeeded, and errors lists the rest.
{
"itemIds": [
"zw5FD5HGcfE3",
"kP3mNq8rT2xY"
]
}{
"archivedCount": 3,
"errors": [
"example-string"
],
"message": "Successfully archived 3 items"
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Return the groups in a proposal, across all Scope of Work pages, with their Public IDs and settings. Line items are not included; use GetGroup or ListItems with a returned group id to read line items and their prices. Archived groups are left out unless you pass archived.
falsedefaulttrueanyascdefaultdescorder_keydefaultnamecreated_atupdated_atnull{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Set the display order of groups. Send groupIds as the Public IDs of the groups in the order you want; the first id is shown first. Groups stay on their current Scope of Work page, so list groups from the same page together. Every id must be a group in this proposal, otherwise the request fails with 400 and nothing changes. To move one group, use MoveGroup. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"groupIds": [
"sL6mScw17PKV",
"RCNMjEEJrf7e"
]
}{
"data": {
"reorderedCount": 2
},
"message": "Groups reordered successfully"
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Return the line items in one group, in display order by default. Each line item includes its Public ID (id) and its price. For fixed prices, price.value is in dollars, not cents. To list a line item's modifications, use ListModifications. Archived and deleted line items are not included. Use a returned id with UpdateItem (PATCH /api/items/{id}) to change a line item's price.
ascdefaultdescorder_keydefaultnamecreated_atupdated_atsinglemultipleloose{
"data": [
{
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {},
"isRange": true,
"maxValue": 100,
"quantity": {},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
]
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Set the display order of line items inside one group. Send itemIds as the Public IDs of the group's line items in the order you want; the first id is shown first. Every id must be a line item in this group, otherwise the request fails with 400 and nothing changes. Line items you leave out keep their current position value. To move one line item, or move it into a different group, use MoveItem. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"itemIds": [
"qeP5CKvwBveC",
"N66wN1Yhese9",
"Vv5EYHv5aNEx"
]
}{
"data": {
"reorderedCount": 3
},
"message": "Items reordered successfully"
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Create a new line item. Send exactly one of parent_group (the Public ID of a group in a proposal, for example zw5FD5HGcfE3) or in_library: true (saves the line item to your organization's library). The line item fields go inside "item". A library line item created this way shows up in the Line Items library and in proposal search. item.name and item.price are required. price needs model and, for every model except none, frequency. For fixed and percent, value is also required. For fixed, value is the unit price in dollars (major currency units), not cents. For percent, value is a whole-number percent (15 = 15%). item.tags is an array of strings and sets the tags. item.externalItemId is your own part number or SKU. item.internalCost is the internal cost in dollars ({ "amount": 40 }), when the profit margins add-on is on. To change any of these later, including tags, PATCH /api/items/{id} with a flat body (no "item" wrapper). Sending tags there replaces the whole list. Library example: { "in_library": true, "item": { "name": "Indoor camera", "description": "<p>4K dome camera.</p>", "price": { "model": "fixed", "value": 499, "frequency": "once" }, "tags": ["cameras", "indoor"], "externalItemId": "CAM-100", "internalCost": { "amount": 210 } } }. Proposal example: { "parent_group": "zw5FD5HGcfE3", "item": { "name": "Website design", "price": { "model": "fixed", "value": 2500, "frequency": "once" } } }. Create one line item per request. If the library already has that name, the response is 409 and includes existingItemId; PATCH that id to update it. To place a line item next to an existing item, or to create a group or side-by-side on a proposal, POST /api/proposals/{id}/items is usually simpler. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"item": {
"name": "example-string",
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"discountExempt": true,
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internal_cost": {
"amount": 100
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"isOptional": true,
"isSelected": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"markupExempt": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"source_library_item_id": "example-string",
"startExpanded": true,
"tags": [
"example-string"
],
"taxExempt": true,
"terms": "example-string"
},
"in_library": true,
"parent_group": "zw5FD5HGcfE3"
}singlemultipleloose{
"data": {
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass that object's Public ID (the id the API returned), not the editor Item ID field (externalItemId, your own SKU or CRM id). Line item: GET /api/items/zw5FD5HGcfE3 returns its price, settings, parent_id (the group's Public ID), children (its modifications), and childCount. Modification: GET /api/items/Qm7rT2vXk9Lp (the modification's Public ID) returns the modification, with parent_id set to its line item. GetModification returns the same data. Side-by-side: GET /api/items/Hs3kW8nYb4Rd (the side-by-side's Public ID) returns its id, name, description, kind "side_by_side", and selectionType. Its columns and features are not included in this response.
{
"item": {
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": "Item not found"
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Change an existing item in place, including its price. Only the fields you send change. The body shape depends on the kind of item. LINE ITEM (and modification): send a flat UpdateLineItemApiInput body, with no "item" wrapper. To change the cost, send price. price is a full replacement, so include model, value, and frequency together. For a fixed price, value is the unit price in major currency units (dollars for USD), not cents. Example that sets the price to $379 one-time: { "price": { "model": "fixed", "value": 379, "frequency": "once" } }. For a percent price, value is a whole-number percent (15 = 15%). Sending only { "price": { "value": 379 } } does not update the price; model is required. SIDE-BY-SIDE: wrap the fields in "item": { "item": { "name", "html", "attrs", "order_key" } }. attrs is merged per key, so keys you leave out are kept. attrs.columns replaces the whole columns array: read the current columns with GetProposal, change them, and send the complete array back, keeping each column's id. Each column has name, price (a number in dollars), frequency, and feeType (fixed, text, or none). Example: { "item": { "attrs": { "columns": [ { "id": "3f2c...", "name": "Basic", "price": 499, "frequency": "monthly", "feeType": "fixed" } ] } } }. To recolor a side-by-side, set item.attrs.theme to a built-in id (metals, ocean, forest, sunset, monochrome, pastel, neon, earth, berry, corporate) without resending columns. Or set item.attrs.design for a custom theme (container, featuresColumn, heading, and a columns palette that cycles). A design object on an individual column overrides that column. theme and design are request-only — the saved item stores the painted colors, not the theme id. The {id} is the Public ID the API returns (for example zw5FD5HGcfE3), not the editor field labeled "Item ID" (externalItemId). To set your own id, send externalItemId (printable characters, including spaces and punctuation; max 255; control characters and non-ASCII are not allowed; null or "" clears it). tags replaces the tag list; omit tags to leave them unchanged. Send tags: [] to clear them. The same call updates a library line item or library side-by-side when {id} is that library entry's Public ID. Proposals that are pending signature, won, or lost cannot be edited (409 PROPOSAL_LOCKED). The same applies when the customer-visible version of a versioned proposal is locked.
{
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"discountExempt": true,
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internal_cost": {
"amount": 100
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"isOptional": true,
"isSelected": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"markupExempt": true,
"modificationsLabel": "example-string",
"name": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"taxExempt": true,
"terms": "example-string"
}{
"item": {
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "DUPLICATE_NAME",
"existingItemId": "example-string",
"message": "A line item with the name \"Item Name\" already exists in the library."
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass that object's Public ID (the id the API returned), not the editor Item ID field (externalItemId). Line item: DELETE /api/items/zw5FD5HGcfE3. Side-by-side: DELETE /api/items/Hs3kW8nYb4Rd (the side-by-side's Public ID). Modification: DELETE /api/items/Qm7rT2vXk9Lp (the modification's Public ID). The object is soft-deleted: it disappears from the proposal and from API responses, and the proposal totals are recalculated. To remove it but keep the option to bring it back, use ArchiveItem and UnarchiveItem instead. Requires permission to delete proposals.
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass that object's Public ID (the id the API returned), not the editor Item ID field (externalItemId). Line item: POST /api/items/zw5FD5HGcfE3/archive. Side-by-side: POST /api/items/Hs3kW8nYb4Rd/archive (the side-by-side's Public ID). Modification: POST /api/items/Qm7rT2vXk9Lp/archive (the modification's Public ID). Archiving removes the object from the proposal in a way you can undo. Archived objects are hidden from the proposal and left out of list responses. Bring one back with UnarchiveItem. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass the Public ID of the object to copy (the id the API returned), not the editor Item ID field (externalItemId). Line item: POST /api/items/zw5FD5HGcfE3/duplicate with an empty body places the copy right after the original in the same group, named "<original name> - Copy", with its modifications copied too. Side-by-side: POST /api/items/Hs3kW8nYb4Rd/duplicate with an empty body adds "Copy of <original name>" at the end of the same Scope of Work page, with the same columns and features. The response includes attrs (columns and features). Modification: POST /api/items/Qm7rT2vXk9Lp/duplicate with an empty body places the copy right after the original under the same line item, named "<original name> - Copy". A modification can only be copied within its own proposal; to move it to another proposal, copy its parent line item. To copy a line item or side-by-side into another proposal, send proposalId (Public ID of the destination proposal) and parent_item_id (Public ID of the destination group for a line item, or of a Scope of Work page for a side-by-side). A copy into another proposal keeps the original name unless you send name. The destination cannot be pending signature, won, or lost. Line items only: toLibrary true saves the line item to your library, and toItem overwrites an existing line item with this one's content. To change the copy's price afterwards, PATCH /api/items/{id} (line item or side-by-side) or PATCH /api/items/{id}/modifications/{modificationId} (modification) with the id returned here.
{
"includeModifiers": true,
"name": "Frontend Development - Copy",
"orderKey": 100,
"parent_item_id": "example-string",
"proposalId": "aB3dE5fG7hJ9",
"tags": [
"example-string"
],
"toItem": "example-string",
"toLibrary": true
}{
"item": {
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass the Public ID of the object to move (the id the API returned), not the editor Item ID field (externalItemId). after_id decides the new position. Line item: POST /api/items/zw5FD5HGcfE3/move with after_id set to another line item's Public ID (placed right after it, moving into that line item's group if different), a group's Public ID (placed first in that group), or null (placed first in its current group). Side-by-side: POST /api/items/Hs3kW8nYb4Rd/move with after_id set to the Public ID of another side-by-side on the same Scope of Work page (placed right after it), or null (placed first on the page). Do not pass a group's Public ID for a side-by-side. Modification: POST /api/items/Qm7rT2vXk9Lp/move with after_id set to the Public ID of another modification on the same line item (placed right after it), or null (placed first under its line item). The price and other settings do not change. To set the order of many line items at once, use ReorderItems. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"after_id": "ijklmnop5678"
}{
"data": {
"id": "zw5FD5HGcfE3"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass the archived object's Public ID (the id the API returned), not the editor Item ID field (externalItemId). Line item: POST /api/items/zw5FD5HGcfE3/unarchive. Side-by-side: POST /api/items/Hs3kW8nYb4Rd/unarchive (the side-by-side's Public ID). Modification: POST /api/items/Qm7rT2vXk9Lp/unarchive (the modification's Public ID). The object shows in the proposal again, with the price and settings it had when archived. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Archive more than one library entry in one call. itemIds are Public IDs returned by the API (for example zw5FD5HGcfE3), not the editor Item ID field (externalItemId). Each id must belong to your organization's library. Line items, groups, and pages are accepted. Archiving hides an entry so it can be restored; it is not a permanent delete. Up to 2000 ids per request. Requires the Manage Library permission. A partial failure still returns 200: archivedCount is how many succeeded, and errors lists the rest.
{
"itemIds": [
"zw5FD5HGcfE3",
"kP3mNq8rT2xY"
]
}{
"archivedCount": 3,
"errors": [
"example-string"
],
"message": "Successfully archived 3 items"
}{
"error": {
"code": "VALIDATION_ERROR",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "FORBIDDEN",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}List line items in your organization's library. Each item's id is its Public ID. externalItemId is the editor Item ID (your part number or SKU), and price is the library price. Use externalItemId to look up one part. Omit it to page through the library. Results stay in your organization. Up to 100 items per request; use offset with pagination.total to read the rest.
ascdefaultdescorder_keydefaultnamecreated_atupdated_atsinglemultipleloose{
"data": [
{
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {},
"isRange": true,
"maxValue": 100,
"quantity": {},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
],
"pagination": {}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Look up a line item name in your organization's library before creating one. Send the name as a query parameter. exists is true when a library line item already uses that name, and itemId is that item's Public ID (the id the API returns, not the editor Item ID / externalItemId). CreateItem with in_library true also returns 409 DUPLICATE_NAME and existingItemId when the name is taken; this call is the check you can make first.
{
"exists": true,
"itemId": "example-string"
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass that object's Public ID (the id the API returned), not the editor Item ID field (externalItemId, your own SKU or CRM id). Line item: GET /api/items/zw5FD5HGcfE3 returns its price, settings, parent_id (the group's Public ID), children (its modifications), and childCount. Modification: GET /api/items/Qm7rT2vXk9Lp (the modification's Public ID) returns the modification, with parent_id set to its line item. GetModification returns the same data. Side-by-side: GET /api/items/Hs3kW8nYb4Rd (the side-by-side's Public ID) returns its id, name, description, kind "side_by_side", and selectionType. Its columns and features are not included in this response.
{
"item": {
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": "Item not found"
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Change an existing item in place, including its price. Only the fields you send change. The body shape depends on the kind of item. LINE ITEM (and modification): send a flat UpdateLineItemApiInput body, with no "item" wrapper. To change the cost, send price. price is a full replacement, so include model, value, and frequency together. For a fixed price, value is the unit price in major currency units (dollars for USD), not cents. Example that sets the price to $379 one-time: { "price": { "model": "fixed", "value": 379, "frequency": "once" } }. For a percent price, value is a whole-number percent (15 = 15%). Sending only { "price": { "value": 379 } } does not update the price; model is required. SIDE-BY-SIDE: wrap the fields in "item": { "item": { "name", "html", "attrs", "order_key" } }. attrs is merged per key, so keys you leave out are kept. attrs.columns replaces the whole columns array: read the current columns with GetProposal, change them, and send the complete array back, keeping each column's id. Each column has name, price (a number in dollars), frequency, and feeType (fixed, text, or none). Example: { "item": { "attrs": { "columns": [ { "id": "3f2c...", "name": "Basic", "price": 499, "frequency": "monthly", "feeType": "fixed" } ] } } }. To recolor a side-by-side, set item.attrs.theme to a built-in id (metals, ocean, forest, sunset, monochrome, pastel, neon, earth, berry, corporate) without resending columns. Or set item.attrs.design for a custom theme (container, featuresColumn, heading, and a columns palette that cycles). A design object on an individual column overrides that column. theme and design are request-only — the saved item stores the painted colors, not the theme id. The {id} is the Public ID the API returns (for example zw5FD5HGcfE3), not the editor field labeled "Item ID" (externalItemId). To set your own id, send externalItemId (printable characters, including spaces and punctuation; max 255; control characters and non-ASCII are not allowed; null or "" clears it). tags replaces the tag list; omit tags to leave them unchanged. Send tags: [] to clear them. The same call updates a library line item or library side-by-side when {id} is that library entry's Public ID. Proposals that are pending signature, won, or lost cannot be edited (409 PROPOSAL_LOCKED). The same applies when the customer-visible version of a versioned proposal is locked.
{
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"discountExempt": true,
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internal_cost": {
"amount": 100
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"isOptional": true,
"isSelected": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"markupExempt": true,
"modificationsLabel": "example-string",
"name": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"taxExempt": true,
"terms": "example-string"
}{
"item": {
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "DUPLICATE_NAME",
"existingItemId": "example-string",
"message": "A line item with the name \"Item Name\" already exists in the library."
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass that object's Public ID (the id the API returned), not the editor Item ID field (externalItemId). Line item: DELETE /api/items/zw5FD5HGcfE3. Side-by-side: DELETE /api/items/Hs3kW8nYb4Rd (the side-by-side's Public ID). Modification: DELETE /api/items/Qm7rT2vXk9Lp (the modification's Public ID). The object is soft-deleted: it disappears from the proposal and from API responses, and the proposal totals are recalculated. To remove it but keep the option to bring it back, use ArchiveItem and UnarchiveItem instead. Requires permission to delete proposals.
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass that object's Public ID (the id the API returned), not the editor Item ID field (externalItemId). Line item: POST /api/items/zw5FD5HGcfE3/archive. Side-by-side: POST /api/items/Hs3kW8nYb4Rd/archive (the side-by-side's Public ID). Modification: POST /api/items/Qm7rT2vXk9Lp/archive (the modification's Public ID). Archiving removes the object from the proposal in a way you can undo. Archived objects are hidden from the proposal and left out of list responses. Bring one back with UnarchiveItem. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass the Public ID of the object to copy (the id the API returned), not the editor Item ID field (externalItemId). Line item: POST /api/items/zw5FD5HGcfE3/duplicate with an empty body places the copy right after the original in the same group, named "<original name> - Copy", with its modifications copied too. Side-by-side: POST /api/items/Hs3kW8nYb4Rd/duplicate with an empty body adds "Copy of <original name>" at the end of the same Scope of Work page, with the same columns and features. The response includes attrs (columns and features). Modification: POST /api/items/Qm7rT2vXk9Lp/duplicate with an empty body places the copy right after the original under the same line item, named "<original name> - Copy". A modification can only be copied within its own proposal; to move it to another proposal, copy its parent line item. To copy a line item or side-by-side into another proposal, send proposalId (Public ID of the destination proposal) and parent_item_id (Public ID of the destination group for a line item, or of a Scope of Work page for a side-by-side). A copy into another proposal keeps the original name unless you send name. The destination cannot be pending signature, won, or lost. Line items only: toLibrary true saves the line item to your library, and toItem overwrites an existing line item with this one's content. To change the copy's price afterwards, PATCH /api/items/{id} (line item or side-by-side) or PATCH /api/items/{id}/modifications/{modificationId} (modification) with the id returned here.
{
"includeModifiers": true,
"name": "Frontend Development - Copy",
"orderKey": 100,
"parent_item_id": "example-string",
"proposalId": "aB3dE5fG7hJ9",
"tags": [
"example-string"
],
"toItem": "example-string",
"toLibrary": true
}{
"item": {
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass the Public ID of the object to move (the id the API returned), not the editor Item ID field (externalItemId). after_id decides the new position. Line item: POST /api/items/zw5FD5HGcfE3/move with after_id set to another line item's Public ID (placed right after it, moving into that line item's group if different), a group's Public ID (placed first in that group), or null (placed first in its current group). Side-by-side: POST /api/items/Hs3kW8nYb4Rd/move with after_id set to the Public ID of another side-by-side on the same Scope of Work page (placed right after it), or null (placed first on the page). Do not pass a group's Public ID for a side-by-side. Modification: POST /api/items/Qm7rT2vXk9Lp/move with after_id set to the Public ID of another modification on the same line item (placed right after it), or null (placed first under its line item). The price and other settings do not change. To set the order of many line items at once, use ReorderItems. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"after_id": "ijklmnop5678"
}{
"data": {
"id": "zw5FD5HGcfE3"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass the archived object's Public ID (the id the API returned), not the editor Item ID field (externalItemId). Line item: POST /api/items/zw5FD5HGcfE3/unarchive. Side-by-side: POST /api/items/Hs3kW8nYb4Rd/unarchive (the side-by-side's Public ID). Modification: POST /api/items/Qm7rT2vXk9Lp/unarchive (the modification's Public ID). The object shows in the proposal again, with the price and settings it had when archived. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Save a new side-by-side in your organization's library. name is required. columns is the list of packages; each column price is a number in dollars (major currency units), not cents. Column and feature ids are generated when you omit them. Ids you send are kept. Example: { "name": "Camera packages", "description": "<p>Choose a package.</p>", "selectionType": "single", "style": "standard", "columns": [ { "name": "Basic", "price": 499, "frequency": "once" }, { "name": "Pro", "price": 899, "frequency": "monthly" } ] }. A library name that already exists returns 409 with existingSideBySideId. To change one later, PATCH /api/items/{id} with an { "item": { ... } } body, using the returned id. To create a side-by-side on a proposal instead, POST /api/proposals/{id}/items with type=side_by_side. tags is an optional list of library tags.
singlemultipleloosestandardcomparisonmetalsoceanforestsunsetmonochromepastelneonearthberrycorporate{
"name": "example-string",
"columns": [
{
"description": "example-string",
"feeType": "fixed",
"frequency": "once",
"id": "example-string",
"includedFeatures": [
"example-string"
],
"isSelected": true,
"name": "example-string",
"price": 499
}
],
"containerDesign": {},
"description": "example-string",
"design": {
"columns": [
{}
],
"container": {},
"featuresColumn": {},
"heading": {}
},
"features": [
{
"id": "example-string",
"name": "example-string",
"order_key": 100
}
],
"featuresColumnDesign": {},
"headingDesign": {},
"selectionType": "single",
"style": "standard",
"tags": [
"example-string"
],
"theme": "metals"
}{
"columns": [
{}
],
"created_at": "2024-01-20T15:30:00Z",
"description": "example-string",
"features": [
{}
],
"id": "Hs3kW8nYb4Rd",
"name": "example-string",
"selectionType": "example-string",
"style": "example-string",
"updated_at": "2024-01-20T15:30:00Z"
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Create a brand-new line item, group, or side-by-side directly inside a proposal (not copied from the library). A line item is added to a group (target_group_id, or the first group by default); a group or side-by-side is added under a Scope of Work page (scope_of_work_page_id, or the first one by default). Pass after_item_id / before_item_id to position the new item relative to an existing one — it then inherits that item's parent. To create a side-by-side on a proposal, send type=side_by_side with a non-empty columns array. To save one in the library instead, POST /api/library/side-by-sides. Each column price is a number in dollars (default 0). Side-by-sides have no URL of their own; to change one later, PATCH /api/items/{id} with an { "item": { ... } } body. Prices are in dollars (major currency units), not cents. Color theme: set theme to a built-in id (metals, ocean, forest, sunset, monochrome, pastel, neon, earth, berry, corporate) or design for a custom theme. theme paints column colors (cycled), the container, and — when style is comparison — the features column and headings. design.container, design.featuresColumn, design.heading, and design.columns (a cycled palette) are the custom settings. A design object on an individual column overrides that column. Send design with theme to start from a built-in theme and override pieces of it.
line_itemgroupside_by_sidesinglemultipleloosestandardcomparisonmetalsoceanforestsunsetmonochromepastelneonearthberrycorporate{
"name": "example-string",
"type": "line_item",
"after_item_id": "example-string",
"before_item_id": "example-string",
"columns": [
{
"name": "example-string",
"description": "example-string",
"design": {
"background": "example-string",
"borderColor": "example-string",
"borderRadius": 100,
"borderWidth": 100,
"buttonColor": "example-string",
"buttonTextColor": "example-string",
"checkmarkColor": "example-string",
"fontColor": "example-string",
"priceColor": "example-string",
"quantityBackgroundColor": "example-string",
"quantityFontColor": "example-string",
"titleColor": "example-string"
},
"feeType": "fixed",
"frequency": "example-string",
"includedFeatures": [
"example-string"
],
"isSelected": true,
"price": 499
}
],
"description": "example-string",
"design": {
"columns": [
{}
],
"container": {
"background": "example-string",
"borderColor": "example-string",
"borderWidth": 100,
"fontColor": "example-string",
"selectionOutlineColor": "example-string",
"showHeader": true,
"sizeModifier": "compact"
},
"featuresColumn": {
"background": "example-string",
"borderColor": "example-string",
"borderRadius": 100,
"borderWidth": 100,
"fontColor": "example-string"
},
"heading": {
"alignment": "left",
"background": "example-string",
"fontColor": "example-string"
}
},
"features": [
{
"name": "example-string",
"order_key": 100
}
],
"optional": true,
"order_key": 100,
"price": {
"frequency": "once",
"model": "fixed",
"quantity": {
"current": 100,
"max": 100,
"min": 100,
"unitLabel": "example-string"
},
"value": 379
},
"scope_of_work_page_id": "example-string",
"selected": true,
"selection_type": "single",
"style": "standard",
"tags": [
"example-string"
],
"target_group_id": "example-string",
"theme": "metals"
}{
"data": {
"id": "example-string",
"name": "example-string",
"order_key": 100,
"type": "example-string"
},
"success": true
}Same URL for a line item, a side-by-side, or a modification. Pass that object's Public ID (the id the API returned), not the editor Item ID field (externalItemId, your own SKU or CRM id). Line item: GET /api/items/zw5FD5HGcfE3 returns its price, settings, parent_id (the group's Public ID), children (its modifications), and childCount. Modification: GET /api/items/Qm7rT2vXk9Lp (the modification's Public ID) returns the modification, with parent_id set to its line item. GetModification returns the same data. Side-by-side: GET /api/items/Hs3kW8nYb4Rd (the side-by-side's Public ID) returns its id, name, description, kind "side_by_side", and selectionType. Its columns and features are not included in this response.
{
"item": {
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": "Item not found"
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass that object's Public ID (the id the API returned), not the editor Item ID field (externalItemId). Line item: DELETE /api/items/zw5FD5HGcfE3. Side-by-side: DELETE /api/items/Hs3kW8nYb4Rd (the side-by-side's Public ID). Modification: DELETE /api/items/Qm7rT2vXk9Lp (the modification's Public ID). The object is soft-deleted: it disappears from the proposal and from API responses, and the proposal totals are recalculated. To remove it but keep the option to bring it back, use ArchiveItem and UnarchiveItem instead. Requires permission to delete proposals.
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass that object's Public ID (the id the API returned), not the editor Item ID field (externalItemId). Line item: POST /api/items/zw5FD5HGcfE3/archive. Side-by-side: POST /api/items/Hs3kW8nYb4Rd/archive (the side-by-side's Public ID). Modification: POST /api/items/Qm7rT2vXk9Lp/archive (the modification's Public ID). Archiving removes the object from the proposal in a way you can undo. Archived objects are hidden from the proposal and left out of list responses. Bring one back with UnarchiveItem. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass the Public ID of the object to copy (the id the API returned), not the editor Item ID field (externalItemId). Line item: POST /api/items/zw5FD5HGcfE3/duplicate with an empty body places the copy right after the original in the same group, named "<original name> - Copy", with its modifications copied too. Side-by-side: POST /api/items/Hs3kW8nYb4Rd/duplicate with an empty body adds "Copy of <original name>" at the end of the same Scope of Work page, with the same columns and features. The response includes attrs (columns and features). Modification: POST /api/items/Qm7rT2vXk9Lp/duplicate with an empty body places the copy right after the original under the same line item, named "<original name> - Copy". A modification can only be copied within its own proposal; to move it to another proposal, copy its parent line item. To copy a line item or side-by-side into another proposal, send proposalId (Public ID of the destination proposal) and parent_item_id (Public ID of the destination group for a line item, or of a Scope of Work page for a side-by-side). A copy into another proposal keeps the original name unless you send name. The destination cannot be pending signature, won, or lost. Line items only: toLibrary true saves the line item to your library, and toItem overwrites an existing line item with this one's content. To change the copy's price afterwards, PATCH /api/items/{id} (line item or side-by-side) or PATCH /api/items/{id}/modifications/{modificationId} (modification) with the id returned here.
{
"includeModifiers": true,
"name": "Frontend Development - Copy",
"orderKey": 100,
"parent_item_id": "example-string",
"proposalId": "aB3dE5fG7hJ9",
"tags": [
"example-string"
],
"toItem": "example-string",
"toLibrary": true
}{
"item": {
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Return the modifications (add-ons, upsells, options, discounts, markups) and dividers under one line item, in order. Each entry includes its Public ID (id) and its current price; for fixed prices, price.value is in dollars, not cents. Archived and deleted modifications are not included. Use a returned id with UpdateModification to change a modification's price.
ascdefaultdescorder_keydefaultnamecreated_atupdated_atmodmod_dividersinglemultipleloose{
"data": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {},
"isRange": true,
"maxValue": 100,
"quantity": {},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"pagination": {
"limit": 20,
"offset": 0,
"page": 1,
"pages": 1,
"total": 5
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Add a modification (an add-on, upsell, option, discount, or markup) to an existing line item. Only name is required. Pricing uses the same price object as line items. If you omit price, the modification is a fixed $0 one-time price. On create, the price fields you send are merged over the defaults (model fixed, value 0, frequency once). For fixed, value is the unit price in dollars (major currency units), not cents. A negative fixed value is a discount. For percent, value is a whole-number percent (10 = 10%) and price.percentageApplyTo says what it is a percent of (line, group, or scope). Example $250 add-on: { "name": "Rush delivery", "price": { "model": "fixed", "value": 250, "frequency": "once" }, "isOptional": true }. Example 10% discount on the parent line item: { "name": "Loyalty discount", "price": { "model": "percent", "value": -10, "frequency": "once", "percentageApplyTo": "line" } }. A modification's quantity multiplies with its parent line item's quantity. Leave price.quantity out (or at 1) for an add-on that applies once per parent unit. Pass kind mod_divider to add a divider instead: a label with no price whose selectionType controls the modifications listed below it. To change the price later, use UpdateModification. Proposals that are pending signature, won, or lost cannot be edited (409).
modmod_dividersinglemultipleloose{
"name": "Rush delivery",
"description": "<p>Delivered within 48 hours.</p>",
"discountExempt": true,
"externalItemId": "example-string",
"isOptional": true,
"isSelected": true,
"kind": "mod",
"label": "example-string",
"markupExempt": true,
"order_key": 1,
"price": {
"frequency": "once",
"model": "fixed",
"percentageApplyTo": "line",
"quantity": {
"current": 100,
"editableByRecipient": true,
"max": 100,
"min": 100,
"unitLabel": "example-string"
},
"value": 250
},
"requireSelection": true,
"selectionType": "single",
"taxExempt": true
}{
"data": {
"id": "zw5FD5HGcfE3",
"kind": "mod",
"name": "example-string"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Return one modification of a line item, including its price. Both path values are Public IDs returned by the API (for example zw5FD5HGcfE3): {id} is the parent line item and {modificationId} is the modification. Neither is the editor field labeled "Item ID"; that field is externalItemId on the modification.
{
"data": {
"created_at": "2024-01-20T15:30:00Z",
"description": "<p>Delivered within 48 hours.</p>",
"discountExempt": true,
"externalItemId": "example-string",
"id": "kP3mNq8rT2xY",
"isOptional": true,
"isSelected": true,
"label": "example-string",
"markupExempt": true,
"name": "Rush delivery",
"parent_id": "example-string",
"price": {
"discount": {},
"frequency": "once",
"isRange": true,
"maxValue": 100,
"model": "fixed",
"percentageApplyTo": "line",
"quantity": {},
"value": 250
},
"taxExempt": true,
"updated_at": "2024-01-20T15:30:00Z"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "NOT_FOUND",
"message": "Modification not found"
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Change an existing modification in place. You can change its price: send price with model, value, and frequency together. price replaces the existing price (range fields such as maxValue and isRange that you leave out are cleared; price.quantity changes only when you send it). For fixed, value is the unit price in dollars (major currency units), not cents. A negative fixed value makes the modification a discount. Sending only { "price": { "value": 1500 } } does not update the price; model is required. For percent, value is a whole-number percent (10 = 10%) and percentageApplyTo says what it is a percent of. Example that sets the price to $1,500 per month: { "price": { "model": "fixed", "value": 1500, "frequency": "monthly" } }. Example $200 discount: { "price": { "model": "fixed", "value": -200, "frequency": "once" } }. Other fields (name, description, isOptional, isSelected, exemptions, externalItemId) change only when you send them. The body is flat, with no "item" wrapper. PATCH /api/items/{modificationId} accepts the same body. Both path values are Public IDs returned by the API (for example zw5FD5HGcfE3), not the editor field labeled "Item ID". To set that field, send externalItemId (printable characters, including spaces and punctuation; max 255; control characters and non-ASCII are not allowed; null or "" clears it). Proposals that are pending signature, won, or lost cannot be edited (409 PROPOSAL_LOCKED). The same applies when the customer-visible version of a versioned proposal is locked.
{
"description": "<p>Delivered within 48 hours.</p>",
"discountExempt": true,
"externalItemId": "example-string",
"isOptional": true,
"isSelected": true,
"label": "example-string",
"markupExempt": true,
"name": "Rush delivery",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {},
"isRange": true,
"maxValue": 100,
"percentageApplyTo": "line",
"quantity": {},
"value": 1500
},
"taxExempt": true
}{
"data": {
"id": "kP3mNq8rT2xY",
"name": "example-string",
"parent_id": "example-string",
"price": {}
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass the Public ID of the object to move (the id the API returned), not the editor Item ID field (externalItemId). after_id decides the new position. Line item: POST /api/items/zw5FD5HGcfE3/move with after_id set to another line item's Public ID (placed right after it, moving into that line item's group if different), a group's Public ID (placed first in that group), or null (placed first in its current group). Side-by-side: POST /api/items/Hs3kW8nYb4Rd/move with after_id set to the Public ID of another side-by-side on the same Scope of Work page (placed right after it), or null (placed first on the page). Do not pass a group's Public ID for a side-by-side. Modification: POST /api/items/Qm7rT2vXk9Lp/move with after_id set to the Public ID of another modification on the same line item (placed right after it), or null (placed first under its line item). The price and other settings do not change. To set the order of many line items at once, use ReorderItems. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"after_id": "ijklmnop5678"
}{
"data": {
"id": "zw5FD5HGcfE3"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Same URL for a line item, a side-by-side, or a modification. Pass the archived object's Public ID (the id the API returned), not the editor Item ID field (externalItemId). Line item: POST /api/items/zw5FD5HGcfE3/unarchive. Side-by-side: POST /api/items/Hs3kW8nYb4Rd/unarchive (the side-by-side's Public ID). Modification: POST /api/items/Qm7rT2vXk9Lp/unarchive (the modification's Public ID). The object shows in the proposal again, with the price and settings it had when archived. Proposals that are pending signature, won, or lost cannot be edited (409).
{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": {
"code": "INTERNAL_ERROR",
"message": "example-string",
"details": {}
}
}Save the complete list of modifications for one line item in a single call. The body is a JSON array, and the result matches it exactly: - An entry whose id is the Public ID of an existing modification on this line item overwrites that modification. - An entry with no id (or an id that is not on this line item) is created as a new modification. - Existing modifications that are not in the array are archived. Sending an empty array archives all of them. - The array order becomes the display order. Send every entry in full. Fields you leave out are not kept from the stored modification; they fall back to defaults: price becomes fixed $0 one-time, isOptional false, isSelected true, and quantity is removed. For fixed prices, price.value is in dollars (major currency units), not cents; a negative value is a discount. For percent, price.value is a whole-number percent (10 = 10%) and percentageApplyTo defaults to line. Example: [ { "id": "kP3mNq8rT2xY", "name": "Rush delivery", "isOptional": true, "price": { "model": "fixed", "value": 250, "frequency": "once" } }, { "name": "Extended warranty", "isOptional": true, "price": { "model": "fixed", "value": 99, "frequency": "annually" } } ]. To change one modification without resending the rest, use UpdateModification instead. Proposals that are pending signature, won, or lost cannot be edited (409 PROPOSAL_LOCKED), and neither can a locked customer version.
modmod_dividersinglemultipleloose[
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"volumePricingEnabled": true,
"volumeTiers": []
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
]{
"error": {
"code": "UNAUTHORIZED",
"message": "example-string",
"details": {}
}
}{
"error": "Item not found"
}{
"error": "Failed to insert modifications"
}Billing frequency for recurring items
onceOne-time onlyweeklyOnce a weekbiweeklyOnce every two weeksmonthlyOnce a monthsemi-monthlyTwice a monthquarterlyOnce every 3 monthssemi-annuallyTwice a yearannuallyOnce a yearevery-2-yearsOnce every 2 yearsevery-3-yearsOnce every 3 yearsevery-4-yearsOnce every 4 yearsevery-5-yearsOnce every 5 yearsevery-6-yearsOnce every 6 yearsevery-7-yearsOnce every 7 yearsevery-8-yearsOnce every 8 yearsevery-9-yearsOnce every 9 yearsevery-10-yearsOnce every 10 years"once"Configuration for discounts applied to line items
unittotallinegroupscopepercentagefixed{
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
}Price configuration - discriminated union of pricing models The 'model' field determines which configuration type is used
{
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{
"unitPrice": 100,
"upTo": 100
}
]
},
"value": 100
}Configuration for item quantity settings
{
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{
"unitPrice": 100,
"upTo": 100
}
]
}A line item (product or service) within a group
singlemultipleloose{
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {},
"isRange": true,
"maxValue": 100,
"quantity": {},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{}
]
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}Request body for updating a line item or modification (PATCH /api/items/{id}). All fields are optional; only the fields you send change. The body is flat (no `item` wrapper). `price` is a full replacement: to change the cost, send the whole price object with `model`, `value` (dollars, not cents), and `frequency`, e.g. `{ "price": { "model": "fixed", "value": 379, "frequency": "once" } }`.
singlemultipleloose{
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"discountExempt": true,
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internal_cost": {
"amount": 100
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"isOptional": true,
"isSelected": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"markupExempt": true,
"modificationsLabel": "example-string",
"name": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{}
]
},
"value": 100
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"taxExempt": true,
"terms": "example-string"
}A modification (child item) of a line item - represents an option or variant
modmod_dividersinglemultipleloose{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"isRange": true,
"maxValue": 100,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{}
]
},
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}Discriminated union for page children (groups and side-by-sides). Both share order_key from the same namespace for interleaved ordering.
{
"displayCost": "show_all",
"id": "example-string",
"isOptional": true,
"isSelected": true,
"kind": "group",
"lineItems": [
{
"children": [
{
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"taxExempt": true,
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"discount": {},
"externalItemId": "example-string",
"hidden": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {},
"internalNotes": "example-string",
"is_archived": true,
"kind": "mod",
"label": "example-string",
"locked": true,
"outOfPocket": {},
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"terms": "example-string",
"updated_at": "example-string"
}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"price": {
"frequency": "once",
"model": "fixed",
"isRange": true,
"maxValue": 100,
"value": 100
},
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {
"added": true,
"amount": 100,
"isSelected": true,
"scope": "unit",
"type": "percentage"
},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {
"amount": 100
},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {
"amount": 100,
"frequency": "once",
"label": "example-string"
},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
],
"name": "example-string",
"selectionType": "single",
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"hidden": true,
"hideQuantities": true,
"in_library": true,
"internalNotes": "example-string",
"is_archived": true,
"linkedScopeId": "example-string",
"locked": true,
"order_key": 100,
"pdfPageBreak": true,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{
"unitPrice": 100,
"upTo": 100
}
]
},
"requireSelection": true,
"startExpanded": true,
"tags": [
"example-string"
],
"updated_at": "example-string"
}Visual design settings for a specific page
fullmediumcompactnarrowleftcenterright{
"backgroundAttachment": "example-string",
"backgroundColor": "example-string",
"backgroundImage": "example-string",
"backgroundOpacity": 100,
"backgroundPosition": "example-string",
"backgroundRepeat": "example-string",
"backgroundSize": "example-string",
"contentAlign": "left",
"contentWidth": "full",
"fontColor": "example-string"
}A page within a proposal. Pages contain the content sections of a proposal.
noneallfirstsinglemultipleloose{
"content": "example-string",
"name": "example-string",
"order_key": 100,
"children": [
{
"displayCost": "show_all",
"id": "example-string",
"isOptional": true,
"isSelected": true,
"kind": "group",
"lineItems": [
{
"children": [
{}
],
"description": "example-string",
"discountExempt": true,
"id": "example-string",
"isOptional": true,
"isSelected": true,
"markupExempt": true,
"name": "example-string",
"taxExempt": true,
"archived_at": "example-string",
"childCount": 100,
"created_at": "example-string",
"discount": {},
"externalItemId": "example-string",
"hasLinkedItems": true,
"hidden": true,
"hideModifications": true,
"in_library": true,
"integrations": {
"quickbooks": {
"productId": "example-string"
}
},
"internalCost": {},
"internalNotes": "example-string",
"is_archived": true,
"label": "example-string",
"linkedLibraryItemId": "example-string",
"locked": true,
"modificationsLabel": "example-string",
"order_key": 100,
"outOfPocket": {},
"parent_id": "example-string",
"requireSelection": true,
"selectionType": "single",
"showCents": true,
"skipRounding": true,
"startExpanded": true,
"tags": [
"example-string"
],
"terms": "example-string",
"updated_at": "example-string"
}
],
"name": "example-string",
"selectionType": "single",
"archived_at": "example-string",
"created_at": "example-string",
"description": "example-string",
"hidden": true,
"hideQuantities": true,
"in_library": true,
"internalNotes": "example-string",
"is_archived": true,
"linkedScopeId": "example-string",
"locked": true,
"order_key": 100,
"pdfPageBreak": true,
"quantity": {
"editableByRecipient": true,
"max": 100,
"min": 100,
"current": 100,
"unitLabel": "example-string",
"volumePricingEnabled": true,
"volumeTiers": [
{
"unitPrice": 100,
"upTo": 100
}
]
},
"requireSelection": true,
"startExpanded": true,
"tags": [
"example-string"
],
"updated_at": "example-string"
}
],
"created_at": "example-string",
"designSettings": {
"backgroundAttachment": "example-string",
"backgroundColor": "example-string",
"backgroundImage": "example-string",
"backgroundOpacity": 100,
"backgroundPosition": "example-string",
"backgroundRepeat": "example-string",
"backgroundSize": "example-string",
"contentAlign": "left",
"contentWidth": "full",
"fontColor": "example-string"
},
"discounts": [
{
"amount": "example-string",
"frequency": "example-string",
"id": "example-string",
"type": "fixed"
}
],
"displayHeading": true,
"excludeFromPdf": true,
"hideSection": true,
"hideTotalsBottom": true,
"hideTotalsTop": true,
"id": "example-string",
"isScopeOfWork": true,
"isSignaturesPage": true,
"kind": "example-string",
"labels": {
"outOfPocket": "example-string",
"tax": "example-string"
},
"lineItemsStartExpanded": "none",
"markupPercentage": "example-string",
"requireSelection": true,
"salesTaxPercentage": "example-string",
"scopeId": "example-string",
"screenshotUrl": "example-string",
"selectionType": "single",
"showCents": true,
"startNewPdfPage": true,
"tags": [
"example-string"
],
"updated_at": "example-string",
"useRoundedAmounts": true
}Internal (your) cost on a line item or modification. Used by the profit_margins add-on. Never shown to customers. Amount is per unit when the parent has quantity; totals multiply by qty. Frequency follows the parent sell price for profitability rollups. Writable on create/update as `internalCost` or `internal_cost`.
{
"amount": 100
}Out-of-pocket (pass-through) cost on a line item or modification. Fixed dollars only — no ranges, quantity settings, or discounts. Frequency is independent of the parent sell price. When omitted, inherit from the parent line/mod. Label defaults to "Out-of-Pocket" when omitted.
onceweeklybiweeklymonthlysemi-monthlyquarterlysemi-annuallyannuallyevery-2-yearsevery-3-yearsevery-4-yearsevery-5-yearsevery-6-yearsevery-7-yearsevery-8-yearsevery-9-yearsevery-10-years{
"amount": 100,
"frequency": "once",
"label": "example-string"
}Pagination metadata for list endpoints
{
"limit": 20,
"page": 1,
"pages": 8,
"total": 150
}