{
  "openapi": "3.0.0",
  "info": {
    "title": "SmartPricingTable API",
    "version": "1.0.0",
    "description": "API documentation for SmartPricingTable application",
    "contact": {
      "name": "SmartPricingTable Support",
      "url": "https://smartpricingtable.com"
    }
  },
  "servers": [
    {
      "url": "http://localhost:3000",
      "description": "Development server"
    }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "JWT access token obtained during authentication"
      },
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "API Key authentication (format: Bearer YOUR_API_KEY)"
      }
    },
    "schemas": {
      "ProposalListItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the proposal"
          },
          "status": {
            "$ref": "#/components/schemas/ProposalDisplayStatus",
            "description": "Current workflow status of the proposal"
          },
          "name": {
            "type": "string",
            "description": "Display name of the proposal"
          },
          "created_by": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ProposalUser"
              },
              {
                "type": "null"
              }
            ],
            "description": "User who created the proposal"
          },
          "updated_by": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ProposalUser"
              },
              {
                "type": "null"
              }
            ],
            "description": "User who last updated the proposal"
          },
          "created_at": {
            "type": "string",
            "description": "ISO 8601 timestamp when the proposal was created"
          },
          "updated_at": {
            "type": "string",
            "description": "ISO 8601 timestamp when the proposal was last updated"
          },
          "archived": {
            "type": "boolean",
            "description": "Whether the proposal is archived"
          },
          "archived_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 timestamp when the proposal was archived, or null if not archived"
          },
          "settings": {
            "$ref": "#/components/schemas/ApiProposalSettings",
            "description": "Display and behavior settings for the proposal (API format, snake_case)"
          },
          "is_template": {
            "type": "boolean",
            "description": "Whether this proposal is a reusable template. List templates via GET /api/proposals?is_template=true."
          },
          "is_starred": {
            "type": "boolean",
            "description": "Whether the current user has starred this proposal"
          },
          "cached_totals": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ProposalCachedTotals"
              },
              {
                "type": "null"
              }
            ],
            "description": "Cached pricing totals for quick display"
          },
          "status_detail": {
            "$ref": "#/components/schemas/ProposalListItemStatusDetail",
            "description": "Status lifecycle details (subset relevant to list views)"
          },
          "allRecipientsSigned": {
            "type": "boolean",
            "description": "True once all recipient signers (client + additional) have signed, meaning only the company is left to sign. Used by getDisplayStatus() to suppress the EXPIRED badge — expiration is a recipient-only concept."
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 timestamp the proposal was sent to the recipient (attrs.timestamps.sent)"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 timestamp all recipient signers completed (attrs.recipientsCompletedAt)"
          },
          "last_activity_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO 8601 timestamp of the most recent recipient-facing activity (view, selection, signing, payment). Powers the \"Last Active\" sort."
          },
          "crm_linked": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "provider": {
                    "type": "string"
                  },
                  "recipient_name": {
                    "type": "string"
                  }
                },
                "required": [
                  "provider"
                ],
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "CRM link info when proposal is linked to a CRM contact/deal"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tags assigned to this proposal"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ],
            "description": "Private, admin-only rich-text note attached to the proposal (HTML). Never shown to recipients. Empty/undefined when no note has been added."
          },
          "proposal_number": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tenant-scoped proposal number when set (attrs.proposalNumber)."
          }
        },
        "required": [
          "id",
          "status",
          "name",
          "created_by",
          "updated_by",
          "created_at",
          "updated_at"
        ],
        "additionalProperties": false,
        "description": "Summary of a proposal for use in list views"
      },
      "Pagination": {
        "type": "object",
        "description": "Pagination metadata for list endpoints",
        "properties": {
          "page": {
            "type": "integer",
            "description": "Current page number",
            "example": 1
          },
          "limit": {
            "type": "integer",
            "description": "Items per page",
            "example": 20
          },
          "total": {
            "type": "integer",
            "description": "Total number of items",
            "example": 150
          },
          "pages": {
            "type": "integer",
            "description": "Total number of pages",
            "example": 8
          }
        }
      },
      "CreateProposalResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for the created proposal"
          }
        },
        "required": [
          "id"
        ],
        "additionalProperties": false,
        "description": "Response from creating a new proposal. Only the ID is returned;\ncallers navigate to the proposal editor which fetches the full detail."
      },
      "ProposalDisplayStatus": {
        "type": "string",
        "enum": [
          "DRAFT",
          "SENT",
          "PENDING",
          "CANCELLED",
          "ON_HOLD",
          "WON",
          "LOST",
          "EXPIRED"
        ],
        "description": "Proposal status"
      },
      "ProposalUser": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Public user ID"
          },
          "name": {
            "type": "string",
            "description": "Full name"
          },
          "email": {
            "type": "string",
            "description": "Email address"
          },
          "avatar_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Avatar image URL"
          }
        },
        "required": [
          "id",
          "name",
          "email"
        ],
        "additionalProperties": false,
        "description": "User profile embedded in proposal responses (used for both created_by and updated_by)"
      },
      "ApiProposalSettings": {
        "type": "object",
        "properties": {
          "signing": {
            "$ref": "#/components/schemas/ApiProposalSigningSettings"
          },
          "recipient": {
            "$ref": "#/components/schemas/ProposalRecipient"
          },
          "notifications": {
            "$ref": "#/components/schemas/ApiProposalNotificationSettings"
          },
          "avoid_line_item_page_breaks": {
            "type": "boolean"
          },
          "hide_pdf_download": {
            "type": "boolean"
          },
          "proposal_continuous_scroll": {
            "type": "boolean"
          },
          "disable_proposal_access": {
            "type": "boolean"
          },
          "include_modifications_in_line_item_price": {
            "type": "boolean"
          },
          "hide_unselected_from_recipient": {
            "type": "boolean"
          },
          "lock_selections_from_recipient": {
            "type": "boolean"
          },
          "currency": {
            "type": "string"
          },
          "expiring_on": {
            "type": [
              "string",
              "null"
            ]
          },
          "email_draft": {
            "type": "object",
            "properties": {
              "recipients": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "name",
                        "email"
                      ],
                      "additionalProperties": false
                    }
                  }
                ]
              },
              "subject": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "last_saved": {
                "type": "string"
              }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": {},
        "description": "API-facing proposal settings (snake_case keys)"
      },
      "ProposalCachedTotals": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string",
            "description": "Currency code for the cached totals (e.g. \"USD\")"
          },
          "updated_at": {
            "type": "string",
            "description": "ISO 8601 timestamp when the cached totals were last recalculated"
          },
          "once": {
            "$ref": "#/components/schemas/ProposalCachedTotalRange",
            "description": "One-time pricing total range"
          },
          "monthly": {
            "$ref": "#/components/schemas/ProposalCachedTotalRange",
            "description": "Monthly recurring pricing total range"
          },
          "quarterly": {
            "$ref": "#/components/schemas/ProposalCachedTotalRange",
            "description": "Quarterly recurring pricing total range"
          },
          "annually": {
            "$ref": "#/components/schemas/ProposalCachedTotalRange",
            "description": "Annually recurring pricing total range"
          }
        },
        "additionalProperties": {
          "anyOf": [
            {
              "$ref": "#/components/schemas/ProposalCachedTotalRange"
            },
            {
              "type": "string"
            },
            {
              "not": {}
            }
          ]
        },
        "description": "Cached pricing totals for the proposal"
      },
      "ProposalListItemStatusDetail": {
        "type": "object",
        "properties": {
          "marked_as_won_method": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "manual",
              "digital_signature",
              "acceptance",
              null
            ],
            "description": "Method used to mark the proposal as won"
          }
        },
        "additionalProperties": false,
        "description": "Subset of status details relevant to list views"
      },
      "ProposalCachedTotalRange": {
        "type": "object",
        "properties": {
          "min": {
            "type": "number",
            "description": "Minimum total amount"
          },
          "max": {
            "type": "number",
            "description": "Maximum total amount"
          }
        },
        "required": [
          "min",
          "max"
        ],
        "additionalProperties": false,
        "description": "A price range with minimum and maximum values"
      },
      "ApiProposalSigningSettings": {
        "type": "object",
        "properties": {
          "use_accept": {
            "type": "boolean",
            "description": "Legacy boolean: true = accept button, false/unset = digital signatures. Prefer `acceptance_method`."
          },
          "acceptance_method": {
            "type": "string",
            "enum": [
              "digital_signatures",
              "accept_button",
              "none"
            ],
            "description": "Acceptance method: 'digital_signatures' | 'accept_button' | 'none'. When unset, falls back to legacy `use_accept`."
          },
          "company_signer": {
            "type": "string"
          },
          "is_contact_signer": {
            "type": "boolean"
          },
          "recipient_signer": {
            "$ref": "#/components/schemas/ApiProposalSigner"
          },
          "additional_signers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiProposalAdditionalSigner"
            }
          },
          "is_multiple_signers": {
            "type": "boolean"
          },
          "custom_company_signer_name": {
            "type": "string"
          },
          "custom_company_signer_email": {
            "type": "string"
          },
          "override_signature_page_defaults": {
            "type": "boolean"
          },
          "signature_page_labels_captured": {
            "type": "boolean",
            "description": "Stamped at create — see `signaturePageLabelsCaptured`."
          },
          "signature_page_agreement_text": {
            "type": "string"
          },
          "signature_page_company_label": {
            "type": "string"
          },
          "signature_page_client_label": {
            "type": "string"
          },
          "signature_page_business_label": {
            "type": "string"
          },
          "signature_page_date_label": {
            "type": "string"
          }
        },
        "additionalProperties": {},
        "description": "API-facing signing settings (snake_case keys)"
      },
      "ProposalRecipient": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Company name of the recipient"
          },
          "address": {
            "type": "string",
            "description": "Mailing address of the recipient company"
          },
          "contact": {
            "$ref": "#/components/schemas/ProposalRecipientContact",
            "description": "Primary contact person at the recipient company"
          },
          "website": {
            "type": "string",
            "description": "Website URL of the recipient company"
          }
        },
        "additionalProperties": {},
        "description": "The client/recipient company for a proposal"
      },
      "ApiProposalNotificationSettings": {
        "type": "object",
        "properties": {
          "override_account_defaults": {
            "type": "boolean"
          },
          "rules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProposalNotificationRule"
            }
          }
        },
        "additionalProperties": false,
        "description": "API-facing notification settings (snake_case keys)"
      },
      "ProposalNotificationRule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for this notification configuration"
          },
          "event": {
            "$ref": "#/components/schemas/ProposalNotificationEvent",
            "description": "The proposal event that triggers this notification"
          },
          "emails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Email addresses to notify when the event occurs"
          }
        },
        "required": [
          "id",
          "event",
          "emails"
        ],
        "additionalProperties": false,
        "description": "Notification configuration for proposal events"
      },
      "ProposalNotificationEvent": {
        "type": "string",
        "enum": [
          "proposal_sent",
          "proposal_opened",
          "proposal_won",
          "proposal_lost"
        ],
        "description": "Type of notification event"
      },
      "ProposalRecipientContact": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Full name of the contact person"
          },
          "email": {
            "type": "string",
            "description": "Email address of the contact person"
          },
          "phone": {
            "type": "string",
            "description": "Phone number of the contact person"
          }
        },
        "additionalProperties": {},
        "description": "Contact person at the recipient company"
      },
      "ApiProposalSigner": {
        "type": "object",
        "properties": {
          "full_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        },
        "additionalProperties": false,
        "description": "API-facing signer (snake_case keys)"
      },
      "ApiProposalAdditionalSigner": {
        "type": "object",
        "properties": {
          "full_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "role": {
            "type": "string"
          }
        },
        "description": "API-facing additional signer (snake_case keys)"
      }
    },
    "responses": {
      "UnauthorizedError": {
        "description": "Authentication required",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "error"
              ],
              "properties": {
                "error": {
                  "type": "object",
                  "required": [
                    "code",
                    "message"
                  ],
                  "properties": {
                    "code": {
                      "type": "string",
                      "enum": [
                        "UNAUTHORIZED"
                      ],
                      "description": "Machine-readable error code"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable error message"
                    },
                    "details": {
                      "type": "object",
                      "description": "Additional error details"
                    }
                  }
                }
              }
            },
            "example": {
              "error": {
                "code": "UNAUTHORIZED",
                "message": "Authentication required"
              }
            }
          }
        }
      },
      "ForbiddenError": {
        "description": "Insufficient permissions",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "error"
              ],
              "properties": {
                "error": {
                  "type": "object",
                  "required": [
                    "code",
                    "message"
                  ],
                  "properties": {
                    "code": {
                      "type": "string",
                      "enum": [
                        "FORBIDDEN"
                      ],
                      "description": "Machine-readable error code"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable error message"
                    },
                    "details": {
                      "type": "object",
                      "description": "Additional error details"
                    }
                  }
                }
              }
            },
            "example": {
              "error": {
                "code": "FORBIDDEN",
                "message": "Insufficient permissions"
              }
            }
          }
        }
      },
      "ValidationError": {
        "description": "Validation error",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "error"
              ],
              "properties": {
                "error": {
                  "type": "object",
                  "required": [
                    "code",
                    "message"
                  ],
                  "properties": {
                    "code": {
                      "type": "string",
                      "enum": [
                        "VALIDATION_ERROR"
                      ],
                      "description": "Machine-readable error code"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable error message"
                    },
                    "details": {
                      "type": "object",
                      "description": "Validation error details"
                    }
                  }
                }
              }
            },
            "example": {
              "error": {
                "code": "VALIDATION_ERROR",
                "message": "Invalid input data",
                "details": {
                  "name": "Name is required"
                }
              }
            }
          }
        }
      },
      "InternalServerError": {
        "description": "Internal server error",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "error"
              ],
              "properties": {
                "error": {
                  "type": "object",
                  "required": [
                    "code",
                    "message"
                  ],
                  "properties": {
                    "code": {
                      "type": "string",
                      "enum": [
                        "INTERNAL_ERROR"
                      ],
                      "description": "Machine-readable error code"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable error message"
                    },
                    "details": {
                      "type": "object",
                      "description": "Additional error details"
                    }
                  }
                }
              }
            },
            "example": {
              "error": {
                "code": "INTERNAL_ERROR",
                "message": "An unexpected error occurred"
              }
            }
          }
        }
      },
      "NotFoundOrNotAuthorizedError": {
        "description": "Not Found - Resource does not exist or access denied",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "error"
              ],
              "properties": {
                "error": {
                  "type": "object",
                  "required": [
                    "code",
                    "message"
                  ],
                  "properties": {
                    "code": {
                      "type": "string",
                      "enum": [
                        "NOT_FOUND"
                      ],
                      "description": "Machine-readable error code"
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable error message"
                    },
                    "details": {
                      "type": "object",
                      "description": "Additional error details"
                    }
                  }
                }
              }
            },
            "example": {
              "error": {
                "code": "NOT_FOUND",
                "message": "Not Authorized or Not Found: Resource {id}"
              }
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "BearerAuth": []
    },
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/api/proposals/{id}/analytics": {
      "get": {
        "operationId": "GetProposalAnalytics",
        "summary": "Get analytics events for a proposal",
        "description": "Retrieve analytics events for a specific proposal. Requires authentication and membership in the proposal's organization (or platform admin).",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal ID",
            "example": "zw5FD5HGcfE3"
          },
          {
            "in": "query",
            "name": "event_type",
            "schema": {
              "type": "string",
              "enum": [
                "proposal_viewed",
                "proposal_sent",
                "status_changed",
                "proposal_signed",
                "pdf_viewed",
                "signature_request_sent"
              ]
            },
            "description": "Filter by event type"
          },
          {
            "in": "query",
            "name": "start_date",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Filter events from this date onwards"
          },
          {
            "in": "query",
            "name": "end_date",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Filter events up to this date"
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "default": 50,
              "minimum": 1,
              "maximum": 200
            },
            "description": "Maximum number of events to return"
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "type": "integer",
              "default": 0,
              "minimum": 0
            },
            "description": "Number of events to skip for pagination"
          }
        ],
        "responses": {
          "200": {
            "description": "Analytics events retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "event_type": {
                            "type": "string"
                          },
                          "event_timestamp": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "user": {
                            "type": "object",
                            "nullable": true,
                            "properties": {
                              "public_id": {
                                "type": "string"
                              },
                              "email": {
                                "type": "string"
                              },
                              "full_name": {
                                "type": "string",
                                "nullable": true
                              }
                            }
                          },
                          "metadata": {
                            "type": "object"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/proposals/{id}/archive": {
      "post": {
        "operationId": "ArchiveProposal",
        "summary": "Archive a proposal",
        "description": "Archive a proposal by setting its archived_at timestamp. Archived proposals are excluded from default listings and become read-only.",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal ID",
            "example": "zw5FD5HGcfE3"
          }
        ],
        "responses": {
          "204": {
            "description": "Proposal archived successfully"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "description": "Not authorized to archive this proposal",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Not authorized to archive this proposal"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Proposal not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Proposal not found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Proposal is already archived",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Proposal is already archived"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/proposals/{id}/bulk-archive": {
      "post": {
        "operationId": "BulkArchiveItems",
        "summary": "Archive multiple items in a proposal",
        "description": "Archive multiple items (line items, groups) from a proposal",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal ID",
            "example": "zw5FD5HGcfE3"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "itemIds"
                ],
                "properties": {
                  "itemIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Array of item IDs to archive",
                    "example": [
                      "abcdefgh1234",
                      "ijklmnop5678"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Items archived successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "archivedCount": {
                      "type": "integer",
                      "description": "Number of items successfully archived",
                      "example": 3
                    },
                    "message": {
                      "type": "string",
                      "description": "Success message",
                      "example": "Successfully archived 3 items"
                    },
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Array of error messages for failed items (only present if some items failed)"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/proposals/{id}/duplicate": {
      "post": {
        "operationId": "DuplicateProposal",
        "summary": "Duplicate a proposal",
        "description": "Create a complete copy of an existing proposal with all its groups, items, and pages",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal ID",
            "example": "zw5FD5HGcfE3"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Name for the duplicated proposal. Default: \"Copy of {original name}\"",
                    "example": "Copy of Q1 2024 Proposal"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Proposal duplicated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "ID of the newly created proposal"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Proposal not found"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/proposals/{id}/export": {
      "get": {
        "operationId": "ExportProposalJSON",
        "summary": "Export a proposal or template as JSON",
        "description": "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.\n",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal or template ID",
            "example": "zw5FD5HGcfE3"
          }
        ],
        "responses": {
          "200": {
            "description": "Importable proposal or template JSON — the same file you get from More → Export as JSON in the app. Ready to import via Create Proposal → Import from JSON.\n",
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string"
                },
                "description": "Suggested download filename for the export",
                "example": "attachment; filename=\"acme_proposal_zw5FD5HGcfE3.json\""
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Proposal export object (same shape as the in-app Export as JSON download). Must include at least name and pages to be importable.\n",
                  "required": [
                    "name",
                    "pages"
                  ],
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "Source proposal or template ID"
                    },
                    "name": {
                      "type": "string",
                      "description": "Proposal or template name"
                    },
                    "status": {
                      "type": "string",
                      "description": "Always DRAFT in exports",
                      "example": "DRAFT"
                    },
                    "is_template": {
                      "type": "boolean",
                      "description": "Whether this export is a template"
                    },
                    "pages": {
                      "type": "array",
                      "description": "Pages, including scope-of-work content, groups, and line items",
                      "items": {
                        "type": "object"
                      }
                    },
                    "settings": {
                      "type": "object",
                      "description": "Proposal settings included in the export"
                    },
                    "design": {
                      "type": "object",
                      "description": "Design settings included in the export"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Proposal not found or not authorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "NOT_FOUND"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/proposals/{id}/items": {
      "post": {
        "summary": "Create a new item in a proposal",
        "description": "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.\n",
        "tags": [
          "Proposals"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Public ID of the proposal."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type",
                  "name"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "line_item",
                      "group",
                      "side_by_side"
                    ],
                    "description": "The kind of item to create."
                  },
                  "name": {
                    "type": "string",
                    "description": "Display name of the item."
                  },
                  "description": {
                    "type": "string",
                    "description": "Optional rich-text/HTML description (stored as the item's content)."
                  },
                  "price": {
                    "type": "object",
                    "description": "Required for type=line_item. Pricing definition.\n",
                    "properties": {
                      "model": {
                        "type": "string",
                        "enum": [
                          "fixed",
                          "percent",
                          "text",
                          "none",
                          "hourly"
                        ]
                      },
                      "value": {
                        "type": "number",
                        "description": "Required for fixed/percent models."
                      },
                      "frequency": {
                        "type": "string",
                        "enum": [
                          "once",
                          "monthly",
                          "annually",
                          "quarterly",
                          "weekly",
                          "biweekly",
                          "semi-monthly",
                          "semi-annually"
                        ],
                        "description": "Required for fixed/percent/text/hourly models."
                      },
                      "quantity": {
                        "type": "object",
                        "properties": {
                          "current": {
                            "type": "number"
                          },
                          "min": {
                            "type": "number"
                          },
                          "max": {
                            "type": "number"
                          },
                          "unitLabel": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  },
                  "optional": {
                    "type": "boolean",
                    "description": "Whether the item is optional (client can toggle it)."
                  },
                  "selected": {
                    "type": "boolean",
                    "description": "Whether an optional item is selected by default."
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Tags to attach to the item."
                  },
                  "target_group_id": {
                    "type": "string",
                    "description": "For type=line_item. Group to add into (default first group)."
                  },
                  "scope_of_work_page_id": {
                    "type": "string",
                    "description": "For type=group or side_by_side. Scope of Work page to add under (default first SOW page)."
                  },
                  "columns": {
                    "type": "array",
                    "description": "Required for type=side_by_side. The selectable packages/columns. Column ids are generated server-side if omitted.\n",
                    "items": {
                      "type": "object",
                      "required": [
                        "name"
                      ],
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "description": {
                          "type": "string"
                        },
                        "price": {
                          "type": "number",
                          "description": "Column price (default 0)."
                        },
                        "frequency": {
                          "type": "string",
                          "description": "e.g. once, monthly, annually (default once)."
                        },
                        "feeType": {
                          "type": "string",
                          "enum": [
                            "fixed",
                            "text",
                            "none"
                          ]
                        },
                        "isSelected": {
                          "type": "boolean"
                        },
                        "includedFeatures": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Feature ids included in this column (comparison style)."
                        }
                      }
                    }
                  },
                  "features": {
                    "type": "array",
                    "description": "For type=side_by_side comparison style — the feature rows.",
                    "items": {
                      "type": "object",
                      "required": [
                        "name"
                      ],
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "order_key": {
                          "type": "number"
                        }
                      }
                    }
                  },
                  "selection_type": {
                    "type": "string",
                    "enum": [
                      "single",
                      "multiple",
                      "loose"
                    ],
                    "description": "For type=side_by_side. How many columns a client may select (default loose)."
                  },
                  "style": {
                    "type": "string",
                    "enum": [
                      "standard",
                      "comparison"
                    ],
                    "description": "For type=side_by_side. Layout style (default standard)."
                  },
                  "after_item_id": {
                    "type": "string",
                    "description": "Place the new item immediately after this existing item (a line item id for type=line_item; a group/side-by-side id for type=group). Inherits that item's parent. Mutually exclusive with before_item_id.\n"
                  },
                  "before_item_id": {
                    "type": "string",
                    "description": "Place the new item immediately before this existing item."
                  },
                  "order_key": {
                    "type": "number",
                    "description": "Optional explicit ordering position. Defaults to appending at the end."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Item created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "type": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "order_key": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (bad type, missing/invalid fields, or no valid parent)."
          },
          "403": {
            "description": "Not authorized to edit the proposal."
          },
          "404": {
            "description": "Proposal (or referenced parent/position item) not found."
          }
        }
      }
    },
    "/api/proposals/{id}/library-insertions": {
      "post": {
        "summary": "Add a library item to a proposal",
        "description": "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.\n",
        "tags": [
          "Proposals"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Public ID of the target proposal."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "type",
                  "library_item_id"
                ],
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "line_item",
                      "group",
                      "page",
                      "side_by_side"
                    ],
                    "description": "The kind of library item to insert."
                  },
                  "library_item_id": {
                    "type": "string",
                    "description": "Public ID of the library item to copy."
                  },
                  "target_group_id": {
                    "type": "string",
                    "description": "For type=line_item only. Public ID of the group in the target proposal to add the line item to. Defaults to the first group in the proposal.\n"
                  },
                  "scope_of_work_page_id": {
                    "type": "string",
                    "description": "For type=group or side_by_side. Public ID of the Scope of Work page to insert under. Defaults to the first Scope of Work page.\n"
                  },
                  "after_item_id": {
                    "type": "string",
                    "description": "Place the new item immediately after this existing item. The new item inherits that item's parent (group for a line item; page for a group/side-by-side) and is given a midpoint order_key. Overrides target_group_id / scope_of_work_page_id. Mutually exclusive with before_item_id.\n"
                  },
                  "before_item_id": {
                    "type": "string",
                    "description": "Place the new item immediately before this existing item. Same rules as after_item_id. Mutually exclusive with it.\n"
                  },
                  "order_key": {
                    "type": "number",
                    "description": "Optional explicit ordering position. Defaults to appending at the end."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Library item inserted into the proposal.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "type": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "order_key": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (missing/invalid type or required target)."
          },
          "403": {
            "description": "Not authorized to edit the target proposal."
          },
          "404": {
            "description": "Proposal or library item not found (or not in the same organization)."
          }
        }
      }
    },
    "/api/proposals/{id}/pdf": {
      "post": {
        "operationId": "GenerateProposalPDF",
        "summary": "Generate proposal PDF",
        "description": "Generate a PDF document for the specified proposal. Returns the PDF as a binary download.",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal ID",
            "example": "zw5FD5HGcfE3"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {}
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "PDF generated successfully",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "description": "Proposal not found"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/proposals/{id}": {
      "get": {
        "operationId": "GetProposal",
        "summary": "Get a single proposal",
        "description": "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.\n",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal ID",
            "example": "zw5FD5HGcfE3"
          }
        ],
        "responses": {
          "200": {
            "description": "Proposal retrieved successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProposalDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Proposal not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "NOT_FOUND"
                        },
                        "message": {
                          "type": "string",
                          "example": "Proposal not found"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "patch": {
        "operationId": "UpdateProposal",
        "summary": "Update a proposal",
        "description": "Update proposal details such as name, description, or client information",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal ID",
            "example": "zw5FD5HGcfE3"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProposalApiInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Proposal updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProposalListItem"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "404": {
            "description": "Proposal not found"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "delete": {
        "operationId": "DeleteProposal",
        "summary": "Delete a proposal",
        "description": "Delete a proposal and all its associated items. The proposal will no longer appear in listings.",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal ID",
            "example": "zw5FD5HGcfE3"
          }
        ],
        "responses": {
          "204": {
            "description": "Proposal deleted successfully"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundOrNotAuthorizedError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/proposals/{id}/star": {
      "post": {
        "operationId": "StarProposal",
        "summary": "Star a proposal",
        "description": "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.",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal ID",
            "example": "zw5FD5HGcfE3"
          }
        ],
        "responses": {
          "200": {
            "description": "Proposal starred successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "is_starred": {
                      "type": "boolean",
                      "example": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundOrNotAuthorizedError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/proposals/{id}/unarchive": {
      "post": {
        "operationId": "UnarchiveProposal",
        "summary": "Unarchive a proposal",
        "description": "Unarchive a proposal by clearing its archived_at timestamp. The proposal will return to active status and become editable again.",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal ID",
            "example": "zw5FD5HGcfE3"
          }
        ],
        "responses": {
          "204": {
            "description": "Proposal unarchived successfully"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "description": "Not authorized to unarchive this proposal",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Not authorized to unarchive this proposal"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Proposal not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Proposal not found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Proposal is not archived",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Proposal is not archived"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/proposals/{id}/unstar": {
      "post": {
        "operationId": "UnstarProposal",
        "summary": "Unstar a proposal",
        "description": "Remove the star from a proposal for the current user. This operation is idempotent - unstarring a proposal that is not starred has no effect.",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Proposal ID",
            "example": "zw5FD5HGcfE3"
          }
        ],
        "responses": {
          "200": {
            "description": "Proposal unstarred successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "is_starred": {
                      "type": "boolean",
                      "example": false
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundOrNotAuthorizedError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    },
    "/api/proposals": {
      "get": {
        "operationId": "ListProposals",
        "summary": "List all proposals",
        "description": "Retrieve a paginated list of proposals for the authenticated user's organization.\nTemplates are excluded by default. Pass `is_template=true` to list reusable templates\ninstead of regular proposals (not both). Use a returned template's `id` with\n`POST /api/proposals` (`templateId`) to create a proposal from that template.\n",
        "tags": [
          "Proposals"
        ],
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "schema": {
              "type": "integer",
              "default": 1,
              "minimum": 1
            },
            "description": "Page number for pagination"
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "default": 20,
              "minimum": 1,
              "maximum": 100
            },
            "description": "Number of items per page"
          },
          {
            "in": "query",
            "name": "search",
            "schema": {
              "type": "string"
            },
            "description": "Search term to filter proposals by name or client",
            "example": "Website"
          },
          {
            "in": "query",
            "name": "sort",
            "schema": {
              "type": "string",
              "enum": [
                "created_at",
                "updated_at",
                "name",
                "status",
                "client_name",
                "sent",
                "expiring_on",
                "completed",
                "last_activity"
              ],
              "default": "created_at"
            },
            "description": "Field to sort by. Date sorts (sent, expiring_on, completed, last_activity) push proposals missing that date to the end; last_activity is the most recent recipient-facing engagement."
          },
          {
            "in": "query",
            "name": "order",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "description": "Sort order"
          },
          {
            "in": "query",
            "name": "status",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "sent",
                "won",
                "lost",
                "cancelled"
              ]
            },
            "description": "Filter by proposal status"
          },
          {
            "in": "query",
            "name": "created_by",
            "schema": {
              "type": "string"
            },
            "description": "Filter by creator's public_id"
          },
          {
            "in": "query",
            "name": "archived",
            "schema": {
              "type": "string",
              "enum": [
                false,
                true,
                "any"
              ],
              "default": false
            },
            "description": "Filter by archive status (false=non-archived, true=archived only, any=both)",
            "example": "false"
          },
          {
            "in": "query",
            "name": "is_template",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "When true, return only template proposals (reusable templates). When omitted or false,\ntemplates are excluded and only regular proposals are returned.\n",
            "example": true
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response with proposals list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ProposalListItem"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      },
      "post": {
        "operationId": "CreateProposal",
        "summary": "Create a new proposal",
        "description": "Create a new proposal for the user's organization.\nTo create from a template, pass `templateId` with a template public ID from\n`GET /api/proposals?is_template=true`. To create a reusable template instead of a\nproposal, set `is_template` to true.\n",
        "tags": [
          "Proposals"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProposalApiInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Proposal created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CreateProposalResponse"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "403": {
            "$ref": "#/components/responses/ForbiddenError"
          },
          "500": {
            "$ref": "#/components/responses/InternalServerError"
          }
        }
      }
    }
  },
  "tags": []
}