engagementKey. Every later get, PDF, duplicate, and renew call uses that key.
There are two ways to create one.
Both need
canWrite: true, a userKey from GET /api/v1/users/list, and an entityKey for an existing client. Leads are not proposal clients. Convert them first. See Leads and deals.
Send versus draft
sendToClient is on every create, duplicate, and renew.
falsesaves a draft. Nothing is emailed. You can open it in OnboardMe and send later.truesends after the record is saved, or submits it for internal approval when the practice requires approval.
engagementKey, and sentToClient is false. Store the key, tell your user it was not sent, and do not create a second proposal to “retry” until you know why the first send failed.
From a template
GET /api/v1/proposals/templates returns the practice templates. Use templateId from that list.
engagementKey. Load GET /api/v1/proposals/{key} if you need the services and prices that the template copied in.
Built without a template
POST /api/v1/proposals requires at least one service. Look up serviceID from GET /api/v1/proposals/services. Optional overrides on a line are quantity, price, taxAmount, packageNumber, isOptional, discountPerc, discountAmount, and serviceDetail.
invoices). These are proposal billings, not POST /api/v1/bills. Each invoice needs billDate, dueDate, and lineItems with amount, narration, and either taxAmount or taxPercent. billNow is 0 (neither), 1 (upfront), or 2 (on completion). Optional ledger ids are extAccountID, extItemID, and extTaxID.
Recurring schedules (recurringBillings). Each needs frequency (daily, weekly, fortnightly, monthly, quarterly, annually), startDate, and lineItems in the same shape. nextRunDate defaults to startDate. billNow here is 0 or 2 only.
XPM jobs (xpmJobs). XPM must be connected. Each job needs name and templateUuid from GET /api/v1/proposals/xpm-job-templates. Optional: categoryId from the categories list, partnerUuid and managerUuid from GET /api/v1/proposals/xpm-staff, dates, description, refNo, budget.
FYI jobs (fyiJobs). FYI Elite must be connected. Each job needs jobName, managerEmail, and partnerEmail. Optional fyiTemplateId and state come from the FYI template and state lists.
Payment details. requestPaymentDetails: true collects a payment method on acceptance. paymentDetailsType is 0 all (default), 1 card, or 2 bank account.
Identity verification. Set identityVerification: true only when you are not also sending an onboarding block. Then verificationMethod is required: Basic, Standard, Enhanced, Comprehensive, Annature Identity Only, or Annature Identity + AML. Individuals and sole traders only. Extra people go in identityPeople (existing entityKey, or name plus surname).
Onboarding after acceptance. The onboarding object uses the same client rows as Onboarding jobs. It is created to send after the client accepts, not immediately. If clients is empty, the proposal client is added for you. Put identity verification on onboarding.clients when this block is present.
Optional header fields: note, startDate, endDate, startOnAcceptance, currencyID, lengthID, terms, refNo, expiryDate, sendSms.
Read, price, and PDF
GET /api/v1/proposals/listpages withpageNumber. Filter withentityKey,searchFilter,statusID,userID, orlastUpdated(UTC).excludeCompleted=truedrops finished proposals. UselastUpdatedthe same way as the client sync watermark.GET /api/v1/proposals/{key}is one proposal: services, billings, jobs, and status.GET /api/v1/proposals/{key}/pricingis the calculated totals. Use this when you display a price, rather than summing line items yourself.GET /api/v1/proposals/{key}/pdfreturns the PDF the client would see.
Duplicate
POST /api/v1/proposals/{key}/duplicate copies services and prices, invoices, recurring schedules, XPM and FYI jobs, packages, terms, and clients into a new proposal. The original is unchanged. sourceMarkedRenewed is always false.
engagementKey. sourceEngagementKey is the one you copied.
Renew
Renew is duplicate plus marking the original Renewed. Preview the signatories first.GET /api/v1/proposals/{key}/renew-previewcompares the proposal’s signatories with the client’s current contacts. WhensignatoriesDifferis true, decide which list the renewal should use.POST /api/v1/proposals/{key}/renewwithuserKey,sendToClient, andsignatorySource.
signatorySource is Proposal (default, keep the previous signatories) or ClientContacts (use the live contact list).
The response matches duplicate, except sourceMarkedRenewed is true when the original was marked Renewed.
When the client accepts
Subscribe toproposal.accepted. It fires when every required signature is complete, not when the proposal is sent. Verify the signature and dedupe on X-Om-Event-Id. See Webhooks.
Proposal reference
Create, from-template, duplicate, renew, pricing, PDF, and the service and job lookups.