Skip to main content
PATCH
/
v3
/
proposals
/
{uuid}
Patch proposal (draft)
curl --request PATCH \
  --url https://api.proposales.com/v3/proposals/{uuid} \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "company_id": 123,
  "language": "<string>",
  "title_md": "<string>",
  "description_md": "<string>",
  "recipient": {},
  "data": {},
  "blocks": [
    {}
  ],
  "attachments": [
    {}
  ],
  "background_image": {},
  "background_video": {},
  "contact_email": "<string>",
  "invoicing_enabled": true,
  "invoicing": {},
  "tax_options": {}
}
'
{
  "proposal": {
    "uuid": "<string>",
    "url": "<string>"
  }
}

Documentation Index

Fetch the complete documentation index at: https://docs.proposales.com/llms.txt

Use this file to discover all available pages before exploring further.

Use this endpoint when you want to change blocks, title, recipient, attachments, or other draft fields without creating a new version. For a new version (duplicate + apply body), use POST /v3/proposals/{uuid}. To update only the JSON data metadata blob with a shallow merge, use Patch proposal data.

Eligibility

  • The proposal must exist (404 if the UUID is unknown).
  • The authenticated user must be allowed to edit the proposal (401 if not).
  • company_id in the body must match the proposal’s company (400 if not).
  • Status must be draft or template. Other statuses return 409 (e.g. active, accepted).
  • withdrawn proposals return 400.

Request body

The body is strict: only documented fields are accepted; extra keys return 400 with error.issues describing each problem (field path and message).
  • company_id (number, required on every request) — must match the proposal’s company.
  • At least one other field is required besides company_id (empty patches are rejected).
All other fields match Create proposal in shape, but they are optional: send only the keys you want to change. Omitted keys are left as-is on the server. Not accepted on this endpoint
  • creator_email — use Create proposal only.
  • status — not used for publishing; see warning above.
language
  • Optional on the patch if the proposal already has a language and you are not changing blocks that depend on the content library.
  • If you send blocks with content_id, you must supply language in the body or the proposal must already have a language stored.

Path

uuid
uuid
required
The UUID of the draft or template to update (same UUID after a successful patch).

Common body fields

The following mirror Create proposal; all are optional except company_id, subject to the rules above.
company_id
number
required
Must equal the proposal’s company_id.
language
string
ISO-style language code (e.g. en, sv). Required when adding/updating blocks with content_id if the proposal has no stored language.
title_md
string
Proposal title as Markdown.
description_md
string
Proposal description as Markdown.
recipient
object
Same shape as Create proposal.
data
object
Proposal metadata when you need to change it together with other draft fields. For a merge-only update of data without touching other fields, prefer PATCH /v3/proposals/{uuid}/data.
blocks
array
Same block shape as Create proposal. If you include blocks, the array replaces the proposal’s entire block list for this update (same as create semantics). Omit blocks to leave the current layout unchanged. To change one block, send the full ordered list with that block updated. For blocks tied to the content library (content_id), the server merges your fields into the stored snapshot for each block you send; it does not accept a sparse “only these block UUIDs” delta.Per-block title, description, and image_uuids are not honored on PATCH — they are owned by the content library and the editor. If sent on a block, they are silently ignored. Update them in the Proposales editor instead.Block identity for editor-edits preservation: matching is strictly by uuid. The editor’s manual edits to a block’s title, description, or images are preserved only when the PATCH block carries the same uuid as the existing block. PATCH blocks without uuid are always treated as brand-new blocks (catalog title/description, server-generated uuid); the order in the resulting proposal mirrors the order in your request body. To update existing blocks, fetch current uuids via GET /v3/proposals/{uuid} and echo them on PATCH. Position in the array is never used to match.
attachments
array
Same attachment shapes as Create proposal.
background_image
object
background_video
object
contact_email
string
invoicing_enabled
boolean
invoicing
object
tax_options
object

Response

proposal
object

Status codes

CodeMeaning
200Draft updated
400Validation failed (strict body, withdrawn, or company_id mismatch). Response may include error.issues with per-field details.
401Missing/invalid token, or user cannot edit this proposal
404Unknown uuid
409Proposal is not draft or template