diff --git a/openapi.yaml b/openapi.yaml index b60efd7e..4e6725b6 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -138,6 +138,8 @@ tags: externalDocs: description: Find out more url: https://getlago.com/docs/api-reference/payment-methods/payment-method-object + - name: quotes + description: Everything about Quote collection externalDocs: description: Lago Github url: https://github.com/getlago @@ -5200,6 +5202,280 @@ paths: $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' + /quotes: + get: + tags: + - quotes + summary: List all quotes + description: |- + This endpoint is used to list all existing quotes. + Quotes are ordered by creation date, from the most recent to the oldest. + This is a premium feature. + operationId: findAllQuotes + parameters: + - $ref: '#/components/parameters/page' + - $ref: '#/components/parameters/per_page' + - name: status[] + in: query + description: Filter quotes by the status of their current version. Possible values are `draft`, `approved` and `voided`. + required: false + explode: true + schema: + type: array + items: + type: string + enum: + - draft + - approved + - voided + - name: order_type[] + in: query + description: Filter quotes by order type. Possible values are `subscription_creation`, `subscription_amendment` and `one_off`. + required: false + explode: true + schema: + type: array + items: + type: string + enum: + - subscription_creation + - subscription_amendment + - one_off + - name: number[] + in: query + description: Filter quotes by their number, as assigned by Lago. + required: false + explode: true + schema: + type: array + items: + type: string + pattern: ^QT-\d{4}-\d{4,}$ + example: + - QT-2026-0001 + - QT-2026-0002 + - name: owner_id[] + in: query + description: Filter quotes by the Lago identifiers of the users owning them. + required: false + explode: true + schema: + type: array + items: + type: string + format: uuid + example: + - 1a901a90-1a90-1a90-1a90-1a901a901a90 + - name: external_customer_id[] + in: query + description: Filter quotes by the external unique identifiers of their customers (provided by your own application). + required: false + explode: true + schema: + type: array + items: + type: string + example: + - external_id_1234 + - name: from_date + in: query + description: Filter quotes created from a specific date. + required: false + explode: true + schema: + type: string + format: date + example: '2026-01-01' + - name: to_date + in: query + description: Filter quotes created up to a specific date. + required: false + explode: true + schema: + type: string + format: date + example: '2026-12-31' + responses: + '200': + description: Quotes + content: + application/json: + schema: + $ref: '#/components/schemas/QuotesPaginated' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '422': + $ref: '#/components/responses/UnprocessableEntity' + /quotes/{lago_id}: + parameters: + - $ref: '#/components/parameters/lago_quote_id' + get: + tags: + - quotes + summary: Retrieve a quote + description: |- + This endpoint retrieves a specific quote, along with its owners and its current version. + This is a premium feature. + operationId: findQuote + responses: + '200': + description: Quote + content: + application/json: + schema: + $ref: '#/components/schemas/Quote' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + /quotes/{lago_id}/versions: + parameters: + - $ref: '#/components/parameters/lago_quote_id' + get: + tags: + - quotes + summary: List all versions of a quote + description: |- + This endpoint is used to list all the versions of a specific quote, from the most recent to the oldest. + The `content` and `billing_items` of each version are omitted; retrieve a version to get them. + This is a premium feature. + operationId: findAllQuoteVersions + parameters: + - $ref: '#/components/parameters/page' + - $ref: '#/components/parameters/per_page' + responses: + '200': + description: Quote versions + content: + application/json: + schema: + $ref: '#/components/schemas/QuoteVersionsPaginated' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + /quote_versions/{lago_id}: + parameters: + - $ref: '#/components/parameters/lago_quote_version_id' + get: + tags: + - quotes + summary: Retrieve a quote version + description: |- + This endpoint retrieves a specific quote version, along with its document `content` and its `billing_items`. + This is a premium feature. + operationId: findQuoteVersion + responses: + '200': + description: Quote version + content: + application/json: + schema: + $ref: '#/components/schemas/QuoteVersion' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + /quote_versions/{lago_id}/approve: + parameters: + - $ref: '#/components/parameters/lago_quote_version_id' + post: + tags: + - quotes + summary: Approve a quote version + description: |- + This endpoint approves a quote version and generates the order form to send to the customer for signature. + Only a `draft` version can be approved, and its `billing_items` must be complete: approval validates them against the catalog and against the customer, and returns a `422` when the deal cannot be executed as quoted. + The `expires_at` of the generated order form is bounded by the deal's own term, so a signing window reaching beyond the day the deal stops being executable is rejected. + A concurrent write on the same quote is reported as a `422` rather than retried, so a duplicated call can fail while the first one is still in flight. + This is a premium feature. + operationId: approveQuoteVersion + requestBody: + description: Approve quote version payload + content: + application/json: + schema: + $ref: '#/components/schemas/QuoteVersionApproveInput' + required: false + responses: + '200': + description: Quote version approved + content: + application/json: + schema: + $ref: '#/components/schemas/QuoteVersion' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '422': + $ref: '#/components/responses/UnprocessableEntity' + /quote_versions/{lago_id}/void: + parameters: + - $ref: '#/components/parameters/lago_quote_version_id' + post: + tags: + - quotes + summary: Void a quote version + description: |- + This endpoint voids a quote version, which makes it definitive: a voided version can neither be edited nor approved again. + Only a `draft` version can be voided through this endpoint, and the resulting `void_reason` is `manual`. An `approved` version is voided by Lago itself, through the order form generated from it. + A concurrent write on the same quote is reported as a `422` rather than retried, so a duplicated call can fail while the first one is still in flight. + This is a premium feature. + operationId: voidQuoteVersion + responses: + '200': + description: Quote version voided + content: + application/json: + schema: + $ref: '#/components/schemas/QuoteVersion' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '422': + $ref: '#/components/responses/UnprocessableEntity' + /quote_versions/{lago_id}/clone: + parameters: + - $ref: '#/components/parameters/lago_quote_version_id' + post: + tags: + - quotes + summary: Clone a quote version + description: |- + This endpoint copies a quote version into a new `draft` version of the same quote, so that the deal can be renegotiated. + Any version of the quote can be cloned, but a quote can only carry one active version: the draft the quote currently holds, if any, is voided with the `superseded` reason. Cloning is therefore rejected with a `422` once a version of the quote has been approved. + A concurrent write on the same quote is reported as a `422` rather than retried, so a duplicated call can fail while the first one is still in flight. + This is a premium feature. + operationId: cloneQuoteVersion + responses: + '200': + description: Quote version cloned + content: + application/json: + schema: + $ref: '#/components/schemas/QuoteVersion' + '401': + $ref: '#/components/responses/Unauthorized' + '403': + $ref: '#/components/responses/Forbidden' + '404': + $ref: '#/components/responses/NotFound' + '422': + $ref: '#/components/responses/UnprocessableEntity' /subscriptions: post: tags: @@ -8782,17 +9058,19 @@ webhooks: responses: '200': description: Return a 200 status to indicate that the data was received successfully - subscription_terminated: + quote_created: post: - operationId: subscriptionTerminated - summary: A subscription has been terminated - description: A subscription has been terminated + operationId: quoteCreated + summary: A new quote has been created + description: |- + A new quote has been created. The payload names the initial `draft` version of the quote, numbered 1. + This is a premium feature. parameters: - $ref: '#/components/parameters/webhook_signature' - $ref: '#/components/parameters/webhook_signature_algorithm' - $ref: '#/components/parameters/webhook_unique_key' requestBody: - description: Details of the subscription + description: Details of the new quote content: application/json: schema: @@ -8801,37 +9079,39 @@ webhooks: - webhook_type - object_type - organization_id - - subscription + - quote properties: webhook_type: type: string enum: - - subscription.terminated + - quote.created object_type: type: string enum: - - subscription + - quote organization_id: type: string format: uuid description: Unique identifier of the organization, created by Lago. example: 1a901a90-1a90-1a90-1a90-1a901a901a90 - subscription: - $ref: '#/components/schemas/SubscriptionWithCustomerObject' + quote: + $ref: '#/components/schemas/QuoteWithVersionObject' responses: '200': description: Return a 200 status to indicate that the data was received successfully - subscription_incomplete: + quote_approved: post: - operationId: subscriptionIncomplete - summary: A subscription is incomplete and waiting for payment - description: A payment-gated subscription has been created in the `incomplete` state and is waiting for the gating payment to succeed before it is activated. + operationId: quoteApproved + summary: A quote has been approved + description: |- + A version of a quote has been approved. An order form is generated from it in the same transaction, so an `order_form.created` event follows. + This is a premium feature. parameters: - $ref: '#/components/parameters/webhook_signature' - $ref: '#/components/parameters/webhook_signature_algorithm' - $ref: '#/components/parameters/webhook_unique_key' requestBody: - description: Details of the subscription + description: Details of the approved quote content: application/json: schema: @@ -8840,37 +9120,39 @@ webhooks: - webhook_type - object_type - organization_id - - subscription + - quote properties: webhook_type: type: string enum: - - subscription.incomplete + - quote.approved object_type: type: string enum: - - subscription + - quote organization_id: type: string format: uuid description: Unique identifier of the organization, created by Lago. example: 1a901a90-1a90-1a90-1a90-1a901a901a90 - subscription: - $ref: '#/components/schemas/SubscriptionWithCustomerObject' + quote: + $ref: '#/components/schemas/QuoteWithVersionObject' responses: '200': description: Return a 200 status to indicate that the data was received successfully - subscription_canceled: + quote_voided: post: - operationId: subscriptionCanceled - summary: A subscription has been canceled - description: A subscription has been canceled before its activation. For payment-gated subscriptions this happens when the gating payment fails or the activation rule expires, in which case the `cancellation_reason` field is set. + operationId: quoteVoided + summary: A quote has been voided + description: |- + A version of a quote has been voided. It is emitted whichever way the version was voided, so read `version.void_reason` to tell them apart: `manual` for an explicit void, `superseded` when the version was cloned into a new draft, `cascade_of_expired` or `cascade_of_voided` when the order form generated from it expired or was voided. + This is a premium feature. parameters: - $ref: '#/components/parameters/webhook_signature' - $ref: '#/components/parameters/webhook_signature_algorithm' - $ref: '#/components/parameters/webhook_unique_key' requestBody: - description: Details of the subscription + description: Details of the voided quote content: application/json: schema: @@ -8879,31 +9161,31 @@ webhooks: - webhook_type - object_type - organization_id - - subscription + - quote properties: webhook_type: type: string enum: - - subscription.canceled + - quote.voided object_type: type: string enum: - - subscription + - quote organization_id: type: string format: uuid description: Unique identifier of the organization, created by Lago. example: 1a901a90-1a90-1a90-1a90-1a901a901a90 - subscription: - $ref: '#/components/schemas/SubscriptionWithCustomerObject' + quote: + $ref: '#/components/schemas/QuoteWithVersionObject' responses: '200': description: Return a 200 status to indicate that the data was received successfully - subscription_started: + subscription_terminated: post: - operationId: subscriptionStarted - summary: An subscription has started - description: An subscription has started + operationId: subscriptionTerminated + summary: A subscription has been terminated + description: A subscription has been terminated parameters: - $ref: '#/components/parameters/webhook_signature' - $ref: '#/components/parameters/webhook_signature_algorithm' @@ -8923,7 +9205,7 @@ webhooks: webhook_type: type: string enum: - - subscription.started + - subscription.terminated object_type: type: string enum: @@ -8938,11 +9220,11 @@ webhooks: responses: '200': description: Return a 200 status to indicate that the data was received successfully - subscription_updated: + subscription_incomplete: post: - operationId: subscriptionUpdated - summary: A subscription has been updated - description: A subscription has been updated + operationId: subscriptionIncomplete + summary: A subscription is incomplete and waiting for payment + description: A payment-gated subscription has been created in the `incomplete` state and is waiting for the gating payment to succeed before it is activated. parameters: - $ref: '#/components/parameters/webhook_signature' - $ref: '#/components/parameters/webhook_signature_algorithm' @@ -8962,7 +9244,7 @@ webhooks: webhook_type: type: string enum: - - subscription.updated + - subscription.incomplete object_type: type: string enum: @@ -8977,11 +9259,11 @@ webhooks: responses: '200': description: Return a 200 status to indicate that the data was received successfully - subscription_termination_alert: + subscription_canceled: post: - operationId: subscriptionTerminationAlert - summary: A subscription will be terminated in the future - description: A subscription will be terminated in the future + operationId: subscriptionCanceled + summary: A subscription has been canceled + description: A subscription has been canceled before its activation. For payment-gated subscriptions this happens when the gating payment fails or the activation rule expires, in which case the `cancellation_reason` field is set. parameters: - $ref: '#/components/parameters/webhook_signature' - $ref: '#/components/parameters/webhook_signature_algorithm' @@ -9001,7 +9283,7 @@ webhooks: webhook_type: type: string enum: - - subscription.termination_alert + - subscription.canceled object_type: type: string enum: @@ -9016,9 +9298,126 @@ webhooks: responses: '200': description: Return a 200 status to indicate that the data was received successfully - subscription_trial_ended: + subscription_started: post: - operationId: subscriptionTrialEnded + operationId: subscriptionStarted + summary: An subscription has started + description: An subscription has started + parameters: + - $ref: '#/components/parameters/webhook_signature' + - $ref: '#/components/parameters/webhook_signature_algorithm' + - $ref: '#/components/parameters/webhook_unique_key' + requestBody: + description: Details of the subscription + content: + application/json: + schema: + type: object + required: + - webhook_type + - object_type + - organization_id + - subscription + properties: + webhook_type: + type: string + enum: + - subscription.started + object_type: + type: string + enum: + - subscription + organization_id: + type: string + format: uuid + description: Unique identifier of the organization, created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + subscription: + $ref: '#/components/schemas/SubscriptionWithCustomerObject' + responses: + '200': + description: Return a 200 status to indicate that the data was received successfully + subscription_updated: + post: + operationId: subscriptionUpdated + summary: A subscription has been updated + description: A subscription has been updated + parameters: + - $ref: '#/components/parameters/webhook_signature' + - $ref: '#/components/parameters/webhook_signature_algorithm' + - $ref: '#/components/parameters/webhook_unique_key' + requestBody: + description: Details of the subscription + content: + application/json: + schema: + type: object + required: + - webhook_type + - object_type + - organization_id + - subscription + properties: + webhook_type: + type: string + enum: + - subscription.updated + object_type: + type: string + enum: + - subscription + organization_id: + type: string + format: uuid + description: Unique identifier of the organization, created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + subscription: + $ref: '#/components/schemas/SubscriptionWithCustomerObject' + responses: + '200': + description: Return a 200 status to indicate that the data was received successfully + subscription_termination_alert: + post: + operationId: subscriptionTerminationAlert + summary: A subscription will be terminated in the future + description: A subscription will be terminated in the future + parameters: + - $ref: '#/components/parameters/webhook_signature' + - $ref: '#/components/parameters/webhook_signature_algorithm' + - $ref: '#/components/parameters/webhook_unique_key' + requestBody: + description: Details of the subscription + content: + application/json: + schema: + type: object + required: + - webhook_type + - object_type + - organization_id + - subscription + properties: + webhook_type: + type: string + enum: + - subscription.termination_alert + object_type: + type: string + enum: + - subscription + organization_id: + type: string + format: uuid + description: Unique identifier of the organization, created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + subscription: + $ref: '#/components/schemas/SubscriptionWithCustomerObject' + responses: + '200': + description: Return a 200 status to indicate that the data was received successfully + subscription_trial_ended: + post: + operationId: subscriptionTrialEnded summary: A subscription trial period has ended description: A subscription trial period has ended parameters: @@ -9386,6 +9785,24 @@ components: schema: type: string example: setup_fee_charge + lago_quote_id: + name: lago_id + in: path + description: Unique identifier assigned to the quote within the Lago application. This ID is exclusively created by Lago and serves as a unique identifier for the quote's record within the Lago system. + required: true + schema: + type: string + format: uuid + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + lago_quote_version_id: + name: lago_id + in: path + description: Unique identifier assigned to the quote version within the Lago application. This ID is exclusively created by Lago and serves as a unique identifier for the quote version's record within the Lago system. + required: true + schema: + type: string + format: uuid + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 subscription_status: name: subscription_status in: query @@ -21047,119 +21464,1115 @@ components: type: boolean description: When set to `true`, the deletion will be cascaded to the children plans. example: true - PlanOverridesObject: + QuoteOrderTypeEnum: + type: string + description: | + The commercial motion the quote describes. It can be any of the following values: + - `subscription_creation`: the quote creates one or more subscriptions. + - `subscription_amendment`: the quote amends an existing subscription, named by the quote's own `lago_subscription_id`. + - `one_off`: the quote bills add-ons once, without any subscription. + enum: + - subscription_creation + - subscription_amendment + - one_off + example: subscription_creation + QuoteBaseObject: type: object - description: Based plan overrides. + required: + - lago_id + - number + - order_type + - lago_customer_id + - lago_subscription_id + - lago_organization_id + - created_at + - updated_at properties: - amount_cents: - type: integer - description: The base cost of the plan, excluding any applicable taxes, that is billed on a recurring basis. This value is defined at 0 if your plan is a pay-as-you-go plan. - example: 10000 - amount_currency: - $ref: '#/components/schemas/Currency' - description: The currency of the plan. It indicates the monetary unit in which the plan's cost, including taxes and usage-based charges, is expressed. - example: USD - description: + lago_id: type: string - description: The description on the plan. - example: Plan for early stage startups. - invoice_display_name: + format: uuid + description: Unique identifier of the quote, created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + number: type: string - example: Startup plan - description: Specifies the name that will be displayed on an invoice. If no value is set for this field, the name of the plan will be used as the default display name. - name: + description: The unique number assigned to the quote by Lago. + example: QT-2026-0001 + order_type: + $ref: '#/components/schemas/QuoteOrderTypeEnum' + lago_customer_id: type: string - example: Startup - description: The name of the plan. - tax_codes: - $ref: '#/components/schemas/TaxCodes' - trial_period: - type: number - description: The duration in days during which the base cost of the plan is offered for free. - example: 5 - minimum_commitment: - $ref: '#/components/schemas/MinimumCommitmentInput' - charges: - type: array - description: Additional usage-based charges for this plan. - items: - type: object - properties: - id: - type: string - format: uuid - description: Unique identifier of the charge created by Lago. - example: 1a901a90-1a90-1a90-1a90-1a901a901a90 - billable_metric_id: - type: string - format: uuid - description: Unique identifier of the billable metric created by Lago. - example: 1a901a90-1a90-1a90-1a90-1a901a901a90 - code: - type: string - description: Unique code identifying the charge within the plan. - example: api_requests_charge - charge_model: - $ref: '#/components/schemas/ChargeModelEnum' - invoice_display_name: - type: string - description: Specifies the name that will be displayed on an invoice. If no value is set for this field, the name of the actual charge will be used as the default display name. - example: Setup - min_amount_cents: - type: integer - description: The minimum spending amount required for the charge, measured in cents and excluding any applicable taxes. It indicates the minimum amount that needs to be charged for each billing period. - example: 0 - properties: - $ref: '#/components/schemas/ChargeObjectProperties' - description: List of all thresholds utilized for calculating the charge. - filters: - type: array - description: List of filters used to apply differentiated pricing based on additional event properties. - items: - $ref: '#/components/schemas/ChargeFilterInput' - tax_codes: - $ref: '#/components/schemas/TaxCodes' - applied_pricing_unit: - type: object - description: Updates the pricing unit conversion rate for this charge. Only applies if the charge has applied pricing unit. - properties: - conversion_rate: - type: string - description: |- - The conversion rate from pricing units to the plan's currency. - This rate determines how many currency units (in the plan's base currency) equal one pricing unit. - For example, if the plan uses USD and the conversion rate is 0.5, then 1 pricing unit = $0.50 USD. - example: '0.5' - fixed_charges: - type: array - description: Fixed charge overrides for the subscription. When `plan_overrides` contains only `fixed_charges` and every entry contains only `id`, `units`, and optionally `apply_units_immediately`, the units are recorded as a per-subscription override without creating a plan override, and subscription-scoped reads return these units. If any entry carries other fields, or `plan_overrides` contains any other key, the request is applied as a full plan override for the subscription instead. - items: - type: object - required: - - id - properties: - id: - type: string - format: uuid - description: Unique identifier of the fixed charge created by Lago. - example: 1a901a90-1a90-1a90-1a90-1a901a901a90 - invoice_display_name: - type: string - description: Specifies the name that will be displayed on an invoice. If no value is set for this field, the name of the actual charge will be used as the default display name. - example: Setup fee - units: - type: number - description: The number of units for the fixed charge. Defaults to 0 if not provided. - example: 1 - default: 0 - apply_units_immediately: - type: boolean - description: Determines if the units should be applied immediately upon assignment or deferred to the next billing cycle. - example: true - properties: - $ref: '#/components/schemas/FixedChargeProperties' - description: List of all thresholds utilized for calculating the fixed charge. - tax_codes: + format: uuid + description: Unique identifier of the customer the quote is addressed to, created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + lago_subscription_id: + type: + - string + - 'null' + format: uuid + description: Unique identifier of the subscription the quote amends, created by Lago. It is set only when the `order_type` is `subscription_amendment`. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + lago_organization_id: + type: string + format: uuid + description: Unique identifier of the organization, created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + created_at: + type: string + format: date-time + description: The date and time in UTC (ISO 8601) when the quote was created. + example: '2026-04-29T08:59:51Z' + updated_at: + type: string + format: date-time + description: The date and time in UTC (ISO 8601) when the quote was last updated. + example: '2026-04-29T08:59:51Z' + QuoteVersionStatusEnum: + type: string + description: | + The status of the quote version. It can be any of the following values: + - `draft`: the version is still editable. + - `approved`: the version has been approved and an order form has been generated from it. + - `voided`: the version is no longer actionable. + + A quote has at most one version in `draft` or `approved` status at any time; all the other versions are `voided`. + enum: + - draft + - approved + - voided + example: draft + QuoteVersionVoidReasonEnum: + type: + - string + - 'null' + description: | + The reason why the quote version was voided. It is `null` unless the `status` is `voided`. It can be any of the following values: + - `manual`: voided explicitly, through the API or the Lago user interface. + - `superseded`: voided because the version was cloned into a new draft. + - `cascade_of_expired`: voided because the order form generated from the version expired. + - `cascade_of_voided`: voided because the order form generated from the version was voided. + enum: + - null + - manual + - superseded + - cascade_of_expired + - cascade_of_voided + example: manual + QuoteVersionObject: + type: object + required: + - lago_id + - lago_quote_id + - lago_organization_id + - version + - status + - currency + - billing_entity_code + - void_reason + - approved_at + - voided_at + - created_at + - updated_at + properties: + lago_id: + type: string + format: uuid + description: Unique identifier of the quote version, created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + lago_quote_id: + type: string + format: uuid + description: Unique identifier of the quote the version belongs to, created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + lago_organization_id: + type: string + format: uuid + description: Unique identifier of the organization, created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + version: + type: integer + description: The number of the version within the quote. It starts at 1 and increases by 1 for every new version created by cloning. + example: 1 + status: + $ref: '#/components/schemas/QuoteVersionStatusEnum' + currency: + $ref: '#/components/schemas/CurrencyOrNull' + description: The currency the version is quoted in. + billing_entity_code: + type: + - string + - 'null' + description: 'Unique code identifying the billing entity that issues the deal. It is resolved rather than stored: the version''s own entity when it names one, then the entity of the subscription being amended for a `subscription_amendment` quote, then the customer''s own. It is `null` when none of them resolves. An amendment cannot name an entity itself, since the subscription it restates is already bound to one, and naming one on an amendment is rejected.' + example: acme_corp + void_reason: + $ref: '#/components/schemas/QuoteVersionVoidReasonEnum' + approved_at: + type: + - string + - 'null' + format: date-time + description: The date and time in UTC (ISO 8601) when the version was approved. It is `null` unless the `status` is `approved`. + example: '2026-04-29T08:59:51Z' + voided_at: + type: + - string + - 'null' + format: date-time + description: The date and time in UTC (ISO 8601) when the version was voided. It is `null` unless the `status` is `voided`. + example: '2026-04-29T08:59:51Z' + created_at: + type: string + format: date-time + description: The date and time in UTC (ISO 8601) when the version was created. + example: '2026-04-29T08:59:51Z' + updated_at: + type: string + format: date-time + description: The date and time in UTC (ISO 8601) when the version was last updated. + example: '2026-04-29T08:59:51Z' + QuoteObject: + allOf: + - $ref: '#/components/schemas/QuoteBaseObject' + - type: object + required: + - current_version + properties: + current_version: + oneOf: + - $ref: '#/components/schemas/QuoteVersionObject' + - type: 'null' + description: The latest version of the quote. Its `content` and `billing_items` are omitted here; retrieve the version to get them. + QuotesPaginated: + type: object + required: + - quotes + - meta + properties: + quotes: + type: array + items: + $ref: '#/components/schemas/QuoteObject' + meta: + $ref: '#/components/schemas/PaginationMeta' + QuoteOwnerObject: + type: object + required: + - lago_id + - email + properties: + lago_id: + type: string + format: uuid + description: Unique identifier of the user owning the quote, created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + email: + type: + - string + - 'null' + format: email + description: The email address of the user owning the quote. + example: sales@getlago.com + QuoteObjectExtended: + allOf: + - $ref: '#/components/schemas/QuoteObject' + - type: object + required: + - owners + properties: + owners: + type: array + description: The users of the organization responsible for the quote. + items: + $ref: '#/components/schemas/QuoteOwnerObject' + Quote: + type: object + required: + - quote + properties: + quote: + $ref: '#/components/schemas/QuoteObjectExtended' + QuoteVersionsPaginated: + type: object + required: + - quote_versions + - meta + properties: + quote_versions: + type: array + items: + $ref: '#/components/schemas/QuoteVersionObject' + meta: + $ref: '#/components/schemas/PaginationMeta' + QuoteBillingItemAddOnObject: + type: object + required: + - id + - localId + - type + - payload + properties: + id: + type: string + format: uuid + description: Unique identifier of the add-on in Lago, pinned when the entry was added to the quote. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + localId: + type: string + description: Identifier of the entry within the quote version, assigned by the Lago user interface. It allows the quote document to reference the entry. + example: b5c1e2a4-4e1e-4a7f-9f0e-9c1a0c7e1f2b + type: + type: string + description: The kind of billing item. + enum: + - add_on + example: add_on + payload: + type: object + description: A snapshot of the add-on as it was added to the quote. `code`, `units`, `unitAmountCents` and `totalAmountCents` are required to approve the version. + properties: + code: + type: string + description: Unique code identifying the add-on. + example: setup_fee + units: + type: number + description: The number of units billed. It must be greater than 0. + example: 1 + unitAmountCents: + type: integer + description: The amount of one unit, in cents, in the currency of the quote version. + example: 10000 + totalAmountCents: + type: integer + description: The total amount billed for the entry, in cents, in the currency of the quote version. + example: 10000 + fromDatetime: + type: + - string + - 'null' + format: date-time + description: The beginning of the period covered by the entry, in UTC (ISO 8601). + example: '2026-01-01T00:00:00Z' + toDatetime: + type: + - string + - 'null' + format: date-time + description: The end of the period covered by the entry, in UTC (ISO 8601). + example: '2026-12-31T23:59:59Z' + overrides: + type: object + description: The deviations from the add-on snapshot negotiated on the quote. Only the properties set here are overridden. + properties: + description: + type: string + description: Overrides the description of the add-on. + example: Onboarding package, discounted for the first year + units: + type: number + description: Overrides the number of units billed. It must be greater than 0. + example: 2 + unitAmountCents: + type: integer + description: Overrides the amount of one unit, in cents. + example: 8000 + totalAmountCents: + type: integer + description: Overrides the total amount billed for the entry, in cents. + example: 16000 + invoiceDisplayName: + type: string + description: Overrides the name of the add-on as it appears on the invoice. + example: Onboarding + fromDatetime: + type: + - string + - 'null' + format: date-time + description: Overrides the beginning of the period covered by the entry, in UTC (ISO 8601). + example: '2026-01-01T00:00:00Z' + toDatetime: + type: + - string + - 'null' + format: date-time + description: Overrides the end of the period covered by the entry, in UTC (ISO 8601). + example: '2026-12-31T23:59:59Z' + QuoteBillingItemPlanObject: + type: object + required: + - id + - type + - payload + properties: + id: + type: string + format: uuid + description: Unique identifier of the plan in Lago, pinned when the entry was added to the quote. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + localId: + type: + - string + - 'null' + description: Identifier of the entry within the quote version, assigned by the Lago user interface. It allows the quote document to reference the entry. + example: b5c1e2a4-4e1e-4a7f-9f0e-9c1a0c7e1f2b + type: + type: string + description: The kind of billing item. + enum: + - plan + example: plan + payload: + type: object + description: A snapshot of the plan as it was added to the quote, and of the subscription to create from it. Additional catalog properties may be present, as only the ones Lago reads when the quote is executed are documented here. `code` is required to approve the version. + properties: + code: + type: string + description: Unique code identifying the plan. + example: premium_plan + subscriptionExternalId: + type: + - string + - 'null' + description: The external unique identifier to assign to the subscription created from the entry. For a `subscription_amendment` quote, it identifies the subscription being amended. + example: sub_1234567890 + subscriptionName: + type: + - string + - 'null' + description: The name to assign to the subscription created from the entry. + example: Premium plan - Acme Corp + billingTime: + type: + - string + - 'null' + description: The billing time of the subscription created from the entry. + enum: + - null + - calendar + - anniversary + example: calendar + startDate: + type: + - string + - 'null' + description: The date and time in UTC (ISO 8601) when the subscription starts. It is optional, and a plan naming none starts the moment the order is executed. + example: '2026-01-01T00:00:00Z' + endDate: + type: + - string + - 'null' + description: The date and time in UTC (ISO 8601) when the subscription ends. Leaving it unset makes the deal open-ended, and on a `subscription_amendment` quote it leaves the amended subscription's own ending date in place. It bounds the deal, so the signing window and the execution date must both fall strictly before it. + example: '2027-01-01T00:00:00Z' + paymentMethodId: + type: + - string + - 'null' + format: uuid + description: Unique identifier of the payment method to charge for the subscription, created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + charges: + type: + - array + - 'null' + description: A snapshot of the usage-based charges of the plan. It pins the charge each entry of `overrides.charges` applies to. + items: + type: object + properties: + id: + type: string + format: uuid + description: Unique identifier of the charge in Lago. It is required to approve the version. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + billableMetric: + type: object + description: The billable metric the charge is based on. + properties: + code: + type: string + description: Unique code identifying the billable metric. It is required to approve the version. + example: api_calls + chargeModel: + type: + - string + - 'null' + description: The pricing model of the charge. + enum: + - null + - standard + - graduated + - graduated_percentage + - package + - percentage + - volume + - custom + - dynamic + example: standard + fixedCharges: + type: + - array + - 'null' + description: A snapshot of the fixed charges of the plan. It pins the fixed charge each entry of `overrides.fixedCharges` applies to. + items: + type: object + properties: + id: + type: string + format: uuid + description: Unique identifier of the fixed charge in Lago. It is required to approve the version. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + addOn: + type: object + description: The add-on the fixed charge is based on. + properties: + code: + type: string + description: Unique code identifying the add-on. It is required to approve the version. + example: seats + chargeModel: + type: + - string + - 'null' + description: The pricing model of the fixed charge. + enum: + - null + - standard + - graduated + - volume + example: standard + overrides: + type: + - object + - 'null' + description: The deviations from the plan snapshot negotiated on the quote. Only the properties set here are overridden. + properties: + amountCents: + type: + - integer + - 'null' + description: Overrides the base amount of the plan, in cents. + example: 50000 + amountCurrency: + $ref: '#/components/schemas/CurrencyOrNull' + description: Overrides the currency the plan is priced in, which is how a catalog plan is quoted in the currency of the deal. The figure in `amountCents` is not converted, it is restated in this currency. It is set only while it differs from the catalog record, and removed once they agree. + invoiceDisplayName: + type: + - string + - 'null' + description: Overrides the name of the plan as it appears on the invoice. + example: Premium + name: + type: + - string + - 'null' + description: Overrides the name of the plan. + example: Premium plan - Acme Corp + description: + type: + - string + - 'null' + description: Overrides the description of the plan. + example: Negotiated premium plan + trialPeriod: + type: + - number + - 'null' + description: Overrides the trial period of the plan, in days. + example: 30 + minimumCommitment: + type: + - object + - 'null' + description: Overrides the minimum commitment of the plan. + properties: + amountCents: + type: + - integer + - 'null' + description: The amount of the minimum commitment, in cents. It must be greater than 0. + example: 100000 + invoiceDisplayName: + type: + - string + - 'null' + description: The name of the minimum commitment as it appears on the invoice. + example: Annual commitment + usageThresholds: + type: + - array + - 'null' + description: Overrides the progressive billing thresholds of the plan. + items: + type: object + required: + - amountCents + properties: + amountCents: + type: integer + description: The usage amount, in cents, at which the threshold is reached. It must be greater than 0. + example: 100000 + recurring: + type: + - boolean + - 'null' + description: Whether the threshold applies to every period, instead of only once. + example: false + thresholdDisplayName: + type: + - string + - 'null' + description: The name of the threshold as it appears on the invoice. + example: First 1,000 EUR of usage + charges: + type: + - array + - 'null' + description: Overrides the usage-based charges of the plan. Each entry applies to the charge of the same billable metric in `payload.charges`. + items: + type: object + required: + - billableMetricCode + properties: + billableMetricCode: + type: string + description: Unique code identifying the billable metric of the charge to override. + example: api_calls + chargeModel: + type: + - string + - 'null' + description: The pricing model of the charge. + enum: + - null + - standard + - graduated + - graduated_percentage + - package + - percentage + - volume + - custom + - dynamic + example: standard + properties: + type: + - object + - 'null' + description: The pricing properties of the charge. Their shape depends on the charge model, and is validated when the quote is executed. + example: + amount: '0.02' + minAmountCents: + type: + - integer + - 'null' + description: The minimum amount billed for the charge, in cents. + example: 10000 + invoiceDisplayName: + type: + - string + - 'null' + description: The name of the charge as it appears on the invoice. + example: API calls + fixedCharges: + type: + - array + - 'null' + description: Overrides the fixed charges of the plan. Each entry applies to the fixed charge of the same add-on in `payload.fixedCharges`. + items: + type: object + required: + - addOnCode + properties: + addOnCode: + type: string + description: Unique code identifying the add-on of the fixed charge to override. + example: seats + units: + type: + - string + - 'null' + description: The number of units billed by the fixed charge. + example: '10' + properties: + type: + - object + - 'null' + description: The pricing properties of the fixed charge. Their shape depends on the charge model, and is validated when the quote is executed. + example: + amount: '5' + invoiceDisplayName: + type: + - string + - 'null' + description: The name of the fixed charge as it appears on the invoice. + example: Seats + QuoteBillingItemCouponObject: + type: object + required: + - id + - localId + - type + - payload + properties: + id: + type: string + format: uuid + description: Unique identifier of the coupon in Lago, pinned when the entry was added to the quote. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + localId: + type: string + description: Identifier of the entry within the quote version, assigned by the Lago user interface. It allows the quote document to reference the entry. + example: b5c1e2a4-4e1e-4a7f-9f0e-9c1a0c7e1f2b + type: + type: string + description: The kind of billing item. + enum: + - coupon + example: coupon + payload: + type: object + description: A snapshot of the coupon as it was added to the quote. `code` and `type` are required to approve the version. + properties: + code: + type: string + description: Unique code identifying the coupon. + example: welcome_offer + type: + type: string + description: Whether the coupon deducts a fixed amount or a percentage. + enum: + - fixed_amount + - percentage + example: fixed_amount + amountCents: + type: + - integer + - 'null' + description: The amount deducted by the coupon, in cents. Only for a `fixed_amount` coupon. + example: 10000 + currency: + $ref: '#/components/schemas/CurrencyOrNull' + description: The currency of `amountCents`. Only for a `fixed_amount` coupon. + percentageRate: + type: + - number + - 'null' + description: The percentage deducted by the coupon. Only for a `percentage` coupon. It must be greater than 0. + example: 10.5 + frequency: + type: + - string + - 'null' + description: How often the coupon is deducted. + enum: + - null + - once + - recurring + - forever + example: once + frequencyDuration: + type: + - integer + - 'null' + description: The number of billing periods the coupon is deducted over. Only for a `recurring` coupon. It must be greater than 0. + example: 3 + overrides: + type: + - object + - 'null' + description: The deviations from the coupon snapshot negotiated on the quote. Only the properties set here are overridden. + properties: + amountCents: + type: + - integer + - 'null' + description: Overrides the amount deducted by the coupon, in cents. + example: 15000 + amountCurrency: + $ref: '#/components/schemas/CurrencyOrNull' + description: Overrides the currency the coupon is priced in, which is how a catalog coupon is quoted in the currency of the deal. The figure in `amountCents` is not converted, it is restated in this currency. It is set only while it differs from the catalog record, and removed once they agree. + percentageRate: + type: + - number + - 'null' + description: Overrides the percentage deducted by the coupon. It must be greater than 0. + example: 15 + frequency: + type: + - string + - 'null' + description: Overrides how often the coupon is deducted. + enum: + - null + - once + - recurring + - forever + example: recurring + frequencyDuration: + type: + - integer + - 'null' + description: Overrides the number of billing periods the coupon is deducted over. It must be greater than 0. + example: 6 + QuoteBillingItemWalletCreditObject: + type: object + required: + - localId + - type + - payload + properties: + localId: + type: string + description: Identifier of the entry within the quote version, assigned by the Lago user interface. It allows the quote document to reference the entry. + example: b5c1e2a4-4e1e-4a7f-9f0e-9c1a0c7e1f2b + type: + type: string + description: The kind of billing item. + enum: + - wallet_credit + example: wallet_credit + payload: + type: object + description: The prepaid credit wallet to create for the customer. Unlike the other billing items, a wallet credit is not built from an existing record, so it carries no `id` and no `overrides`. `paidCredits`, `grantedCredits` and `rateAmount` are required to approve the version. + properties: + paidCredits: + type: + - string + - 'null' + description: The number of credits the customer pays for. + example: '100.0' + grantedCredits: + type: + - string + - 'null' + description: The number of credits granted for free. + example: '20.0' + rateAmount: + type: + - string + - 'null' + description: The value of one credit, in the currency of the wallet. + example: '1.0' + currency: + $ref: '#/components/schemas/CurrencyOrNull' + description: The currency of the wallet. + expirationAt: + type: + - string + - 'null' + format: date-time + description: The date and time in UTC (ISO 8601) when the credits expire. + example: '2027-01-01T00:00:00Z' + appliesTo: + type: + - object + - 'null' + description: The limitations restricting what the credits can be spent on. + properties: + feeTypes: + type: + - array + - 'null' + description: The fee types the credits can be spent on. + items: + type: string + enum: + - charge + - add_on + - subscription + - credit + - commitment + - fixed_charge + - product + example: + - charge + billableMetricCodes: + type: + - array + - 'null' + description: The codes of the billable metrics the credits can be spent on. + items: + type: string + example: + - api_calls + recurringTransactionRules: + type: + - array + - 'null' + description: The rule automatically topping the wallet up. At most one rule is allowed, and its `trigger` is required, to approve the version. + items: + type: object + properties: + trigger: + type: + - string + - 'null' + description: What triggers the top-up. + enum: + - null + - interval + - threshold + example: interval + interval: + type: + - string + - 'null' + description: How often the wallet is topped up. Only for an `interval` trigger. + enum: + - null + - weekly + - monthly + - quarterly + - semiannual + - yearly + example: monthly + thresholdCredits: + type: + - string + - 'null' + description: The credit balance below which the wallet is topped up. Only for a `threshold` trigger. + example: '10.0' + method: + type: + - string + - 'null' + description: Whether the top-up grants a fixed number of credits, or brings the balance up to a target. + enum: + - null + - fixed + - target + example: fixed + targetOngoingBalance: + type: + - string + - 'null' + description: The balance the top-up brings the wallet up to. Only for a `target` method. + example: '100.0' + grantsTargetTopUp: + type: + - boolean + - 'null' + description: Whether the granted credits count towards the target balance. + example: false + paidCredits: + type: + - string + - 'null' + description: The number of credits the customer pays for on every top-up. + example: '100.0' + grantedCredits: + type: + - string + - 'null' + description: The number of credits granted for free on every top-up. + example: '20.0' + startedAt: + type: + - string + - 'null' + format: date-time + description: The date and time in UTC (ISO 8601) when the rule starts applying. + example: '2026-01-01T00:00:00Z' + expirationAt: + type: + - string + - 'null' + format: date-time + description: The date and time in UTC (ISO 8601) when the rule stops applying. + example: '2027-01-01T00:00:00Z' + transactionName: + type: + - string + - 'null' + description: The name given to the wallet transactions created by the rule. + example: Monthly top-up + invoiceRequiresSuccessfulPayment: + type: + - boolean + - 'null' + description: Whether the credits are granted only once the top-up invoice is paid. + example: false + QuoteBillingItems: + type: + - object + - 'null' + description: | + A snapshot of everything the quote bills. Unlike the rest of the Lago API, the keys nested in this object are camelCased: the object is stored and returned as it is authored in the Lago user interface. + + Which top-level keys are present depends on the `order_type` of the parent quote: + - `one_off`: `addOns`. + - `subscription_creation` and `subscription_amendment`: `plans`, plus the optional `coupons` and `walletCredits`. + + Every entry pins the catalog record it was built from through its `id` and its `payload`, so that an approved quote keeps billing what was approved even if the catalog changes afterwards. The optional `overrides` object carries the deviations from that record negotiated on the quote. + + This object is the single source of truth for the term of the deal. Three of its nested dates bound that term, because the execution flow refuses them once past: `plans[].payload.endDate`, `walletCredits[].payload.expirationAt` and the `expirationAt` of a wallet credit's recurring top-up rule. The earliest of them is the day the deal stops being executable, and both the signing window and the execution date must fall strictly before it. A `one_off` quote carries none of them and is never bounded. + + On a `draft` version this object may be incomplete: only the properties documented as required below are enforced on every save, the others are enforced when the version is approved. + properties: + addOns: + type: array + description: The add-ons billed once by a `one_off` quote. At least one entry is required to approve the version. + items: + $ref: '#/components/schemas/QuoteBillingItemAddOnObject' + plans: + type: array + description: The plans subscribed to, or amended, by a `subscription_creation` or `subscription_amendment` quote. At least one entry is required to approve the version. + items: + $ref: '#/components/schemas/QuoteBillingItemPlanObject' + coupons: + type: array + description: The coupons applied to the customer when the quote is executed. + items: + $ref: '#/components/schemas/QuoteBillingItemCouponObject' + walletCredits: + type: array + description: The prepaid credit wallets created for the customer when the quote is executed. + items: + $ref: '#/components/schemas/QuoteBillingItemWalletCreditObject' + QuoteVersionObjectExtended: + allOf: + - $ref: '#/components/schemas/QuoteVersionObject' + - type: object + required: + - content + - billing_items + properties: + content: + type: + - string + - 'null' + description: The HTML body of the quote document, as authored in the Lago user interface. It may reference the entries of `billing_items` through their `localId`. + example:

Quote QT-2026-0001

Prepared for Acme Corp.

+ billing_items: + $ref: '#/components/schemas/QuoteBillingItems' + QuoteVersion: + type: object + required: + - quote_version + properties: + quote_version: + $ref: '#/components/schemas/QuoteVersionObjectExtended' + QuoteVersionApproveInput: + type: object + description: Parameters available when approving a quote version. + required: [] + properties: + expires_at: + type: string + format: date-time + description: The date and time in UTC (ISO 8601) when the order form generated by the approval expires. It must be in the future, and must fall strictly before the day the quoted deal stops being executable, otherwise the approval is rejected with a `422`. That boundary is the earliest of the `endDate` of any quoted plan and the `expirationAt` of any quoted wallet credit or recurring top-up rule. A `one_off` quote carries none of them, so its signing window is never bounded. When `expires_at` is omitted, the order form never expires. + example: '2026-06-30T23:59:59Z' + PlanOverridesObject: + type: object + description: Based plan overrides. + properties: + amount_cents: + type: integer + description: The base cost of the plan, excluding any applicable taxes, that is billed on a recurring basis. This value is defined at 0 if your plan is a pay-as-you-go plan. + example: 10000 + amount_currency: + $ref: '#/components/schemas/Currency' + description: The currency of the plan. It indicates the monetary unit in which the plan's cost, including taxes and usage-based charges, is expressed. + example: USD + description: + type: string + description: The description on the plan. + example: Plan for early stage startups. + invoice_display_name: + type: string + example: Startup plan + description: Specifies the name that will be displayed on an invoice. If no value is set for this field, the name of the plan will be used as the default display name. + name: + type: string + example: Startup + description: The name of the plan. + tax_codes: + $ref: '#/components/schemas/TaxCodes' + trial_period: + type: number + description: The duration in days during which the base cost of the plan is offered for free. + example: 5 + minimum_commitment: + $ref: '#/components/schemas/MinimumCommitmentInput' + charges: + type: array + description: Additional usage-based charges for this plan. + items: + type: object + properties: + id: + type: string + format: uuid + description: Unique identifier of the charge created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + billable_metric_id: + type: string + format: uuid + description: Unique identifier of the billable metric created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + code: + type: string + description: Unique code identifying the charge within the plan. + example: api_requests_charge + charge_model: + $ref: '#/components/schemas/ChargeModelEnum' + invoice_display_name: + type: string + description: Specifies the name that will be displayed on an invoice. If no value is set for this field, the name of the actual charge will be used as the default display name. + example: Setup + min_amount_cents: + type: integer + description: The minimum spending amount required for the charge, measured in cents and excluding any applicable taxes. It indicates the minimum amount that needs to be charged for each billing period. + example: 0 + properties: + $ref: '#/components/schemas/ChargeObjectProperties' + description: List of all thresholds utilized for calculating the charge. + filters: + type: array + description: List of filters used to apply differentiated pricing based on additional event properties. + items: + $ref: '#/components/schemas/ChargeFilterInput' + tax_codes: + $ref: '#/components/schemas/TaxCodes' + applied_pricing_unit: + type: object + description: Updates the pricing unit conversion rate for this charge. Only applies if the charge has applied pricing unit. + properties: + conversion_rate: + type: string + description: |- + The conversion rate from pricing units to the plan's currency. + This rate determines how many currency units (in the plan's base currency) equal one pricing unit. + For example, if the plan uses USD and the conversion rate is 0.5, then 1 pricing unit = $0.50 USD. + example: '0.5' + fixed_charges: + type: array + description: Fixed charge overrides for the subscription. When `plan_overrides` contains only `fixed_charges` and every entry contains only `id`, `units`, and optionally `apply_units_immediately`, the units are recorded as a per-subscription override without creating a plan override, and subscription-scoped reads return these units. If any entry carries other fields, or `plan_overrides` contains any other key, the request is applied as a full plan override for the subscription instead. + items: + type: object + required: + - id + properties: + id: + type: string + format: uuid + description: Unique identifier of the fixed charge created by Lago. + example: 1a901a90-1a90-1a90-1a90-1a901a901a90 + invoice_display_name: + type: string + description: Specifies the name that will be displayed on an invoice. If no value is set for this field, the name of the actual charge will be used as the default display name. + example: Setup fee + units: + type: number + description: The number of units for the fixed charge. Defaults to 0 if not provided. + example: 1 + default: 0 + apply_units_immediately: + type: boolean + description: Determines if the units should be applied immediately upon assignment or deferred to the next billing cycle. + example: true + properties: + $ref: '#/components/schemas/FixedChargeProperties' + description: List of all thresholds utilized for calculating the fixed charge. + tax_codes: $ref: '#/components/schemas/TaxCodes' description: List of taxes applied to the fixed charge. usage_thresholds: @@ -23048,6 +24461,16 @@ components: - type: string - type: object additionalProperties: true + QuoteWithVersionObject: + allOf: + - $ref: '#/components/schemas/QuoteBaseObject' + - type: object + required: + - version + properties: + version: + $ref: '#/components/schemas/QuoteVersionObject' + description: The version of the quote the event happened to. It is not necessarily the current version of the quote, as a `quote.voided` event triggered by a clone names the version that was voided while the quote already carries its replacement. Its `content` and `billing_items` are omitted here; retrieve the version to get them. SubscriptionWithCustomerObject: allOf: - $ref: '#/components/schemas/SubscriptionObject' diff --git a/src/openapi.yaml b/src/openapi.yaml index a28ee9c3..5f564707 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -142,6 +142,8 @@ tags: externalDocs: description: Find out more url: https://getlago.com/docs/api-reference/payment-methods/payment-method-object + - name: quotes + description: Everything about Quote collection paths: /billing_entities: @@ -328,6 +330,20 @@ paths: $ref: "./resources/plan_fixed_charges.yaml" /plans/{code}/fixed_charges/{fixed_charge_code}: $ref: "./resources/plan_fixed_charge.yaml" + /quotes: + $ref: "./resources/quotes.yaml" + /quotes/{lago_id}: + $ref: "./resources/quote.yaml" + /quotes/{lago_id}/versions: + $ref: "./resources/quote_versions.yaml" + /quote_versions/{lago_id}: + $ref: "./resources/quote_version.yaml" + /quote_versions/{lago_id}/approve: + $ref: "./resources/quote_version_approve.yaml" + /quote_versions/{lago_id}/void: + $ref: "./resources/quote_version_void.yaml" + /quote_versions/{lago_id}/clone: + $ref: "./resources/quote_version_clone.yaml" /subscriptions: $ref: "./resources/subscriptions.yaml" /subscriptions/{external_id}: @@ -487,6 +503,12 @@ webhooks: $ref: "./webhooks/plan_updated.yaml" plan_deleted: $ref: "./webhooks/plan_deleted.yaml" + quote_created: + $ref: "./webhooks/quote_created.yaml" + quote_approved: + $ref: "./webhooks/quote_approved.yaml" + quote_voided: + $ref: "./webhooks/quote_voided.yaml" subscription_terminated: $ref: "./webhooks/subscription_terminated.yaml" subscription_incomplete: diff --git a/src/parameters/lago_quote_id.yaml b/src/parameters/lago_quote_id.yaml new file mode 100644 index 00000000..dc92f5d7 --- /dev/null +++ b/src/parameters/lago_quote_id.yaml @@ -0,0 +1,8 @@ +name: lago_id +in: path +description: Unique identifier assigned to the quote within the Lago application. This ID is exclusively created by Lago and serves as a unique identifier for the quote's record within the Lago system. +required: true +schema: + type: string + format: "uuid" + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" diff --git a/src/parameters/lago_quote_version_id.yaml b/src/parameters/lago_quote_version_id.yaml new file mode 100644 index 00000000..41f6bb5a --- /dev/null +++ b/src/parameters/lago_quote_version_id.yaml @@ -0,0 +1,8 @@ +name: lago_id +in: path +description: Unique identifier assigned to the quote version within the Lago application. This ID is exclusively created by Lago and serves as a unique identifier for the quote version's record within the Lago system. +required: true +schema: + type: string + format: "uuid" + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" diff --git a/src/resources/quote.yaml b/src/resources/quote.yaml new file mode 100644 index 00000000..48f19454 --- /dev/null +++ b/src/resources/quote.yaml @@ -0,0 +1,23 @@ +parameters: + - $ref: "../parameters/lago_quote_id.yaml" +get: + tags: + - quotes + summary: Retrieve a quote + description: |- + This endpoint retrieves a specific quote, along with its owners and its current version. + This is a premium feature. + operationId: findQuote + responses: + "200": + description: Quote + content: + application/json: + schema: + $ref: "../schemas/Quote.yaml" + "401": + $ref: "../responses/Unauthorized.yaml" + "403": + $ref: "../responses/Forbidden.yaml" + "404": + $ref: "../responses/NotFound.yaml" diff --git a/src/resources/quote_version.yaml b/src/resources/quote_version.yaml new file mode 100644 index 00000000..062988b7 --- /dev/null +++ b/src/resources/quote_version.yaml @@ -0,0 +1,23 @@ +parameters: + - $ref: "../parameters/lago_quote_version_id.yaml" +get: + tags: + - quotes + summary: Retrieve a quote version + description: |- + This endpoint retrieves a specific quote version, along with its document `content` and its `billing_items`. + This is a premium feature. + operationId: findQuoteVersion + responses: + "200": + description: Quote version + content: + application/json: + schema: + $ref: "../schemas/QuoteVersion.yaml" + "401": + $ref: "../responses/Unauthorized.yaml" + "403": + $ref: "../responses/Forbidden.yaml" + "404": + $ref: "../responses/NotFound.yaml" diff --git a/src/resources/quote_version_approve.yaml b/src/resources/quote_version_approve.yaml new file mode 100644 index 00000000..83c17144 --- /dev/null +++ b/src/resources/quote_version_approve.yaml @@ -0,0 +1,35 @@ +parameters: + - $ref: "../parameters/lago_quote_version_id.yaml" +post: + tags: + - quotes + summary: Approve a quote version + description: |- + This endpoint approves a quote version and generates the order form to send to the customer for signature. + Only a `draft` version can be approved, and its `billing_items` must be complete: approval validates them against the catalog and against the customer, and returns a `422` when the deal cannot be executed as quoted. + The `expires_at` of the generated order form is bounded by the deal's own term, so a signing window reaching beyond the day the deal stops being executable is rejected. + A concurrent write on the same quote is reported as a `422` rather than retried, so a duplicated call can fail while the first one is still in flight. + This is a premium feature. + operationId: approveQuoteVersion + requestBody: + description: Approve quote version payload + content: + application/json: + schema: + $ref: "../schemas/QuoteVersionApproveInput.yaml" + required: false + responses: + "200": + description: Quote version approved + content: + application/json: + schema: + $ref: "../schemas/QuoteVersion.yaml" + "401": + $ref: "../responses/Unauthorized.yaml" + "403": + $ref: "../responses/Forbidden.yaml" + "404": + $ref: "../responses/NotFound.yaml" + "422": + $ref: "../responses/UnprocessableEntity.yaml" diff --git a/src/resources/quote_version_clone.yaml b/src/resources/quote_version_clone.yaml new file mode 100644 index 00000000..c2a79547 --- /dev/null +++ b/src/resources/quote_version_clone.yaml @@ -0,0 +1,27 @@ +parameters: + - $ref: "../parameters/lago_quote_version_id.yaml" +post: + tags: + - quotes + summary: Clone a quote version + description: |- + This endpoint copies a quote version into a new `draft` version of the same quote, so that the deal can be renegotiated. + Any version of the quote can be cloned, but a quote can only carry one active version: the draft the quote currently holds, if any, is voided with the `superseded` reason. Cloning is therefore rejected with a `422` once a version of the quote has been approved. + A concurrent write on the same quote is reported as a `422` rather than retried, so a duplicated call can fail while the first one is still in flight. + This is a premium feature. + operationId: cloneQuoteVersion + responses: + "200": + description: Quote version cloned + content: + application/json: + schema: + $ref: "../schemas/QuoteVersion.yaml" + "401": + $ref: "../responses/Unauthorized.yaml" + "403": + $ref: "../responses/Forbidden.yaml" + "404": + $ref: "../responses/NotFound.yaml" + "422": + $ref: "../responses/UnprocessableEntity.yaml" diff --git a/src/resources/quote_version_void.yaml b/src/resources/quote_version_void.yaml new file mode 100644 index 00000000..57e361b9 --- /dev/null +++ b/src/resources/quote_version_void.yaml @@ -0,0 +1,27 @@ +parameters: + - $ref: "../parameters/lago_quote_version_id.yaml" +post: + tags: + - quotes + summary: Void a quote version + description: |- + This endpoint voids a quote version, which makes it definitive: a voided version can neither be edited nor approved again. + Only a `draft` version can be voided through this endpoint, and the resulting `void_reason` is `manual`. An `approved` version is voided by Lago itself, through the order form generated from it. + A concurrent write on the same quote is reported as a `422` rather than retried, so a duplicated call can fail while the first one is still in flight. + This is a premium feature. + operationId: voidQuoteVersion + responses: + "200": + description: Quote version voided + content: + application/json: + schema: + $ref: "../schemas/QuoteVersion.yaml" + "401": + $ref: "../responses/Unauthorized.yaml" + "403": + $ref: "../responses/Forbidden.yaml" + "404": + $ref: "../responses/NotFound.yaml" + "422": + $ref: "../responses/UnprocessableEntity.yaml" diff --git a/src/resources/quote_versions.yaml b/src/resources/quote_versions.yaml new file mode 100644 index 00000000..0c182fef --- /dev/null +++ b/src/resources/quote_versions.yaml @@ -0,0 +1,27 @@ +parameters: + - $ref: "../parameters/lago_quote_id.yaml" +get: + tags: + - quotes + summary: List all versions of a quote + description: |- + This endpoint is used to list all the versions of a specific quote, from the most recent to the oldest. + The `content` and `billing_items` of each version are omitted; retrieve a version to get them. + This is a premium feature. + operationId: findAllQuoteVersions + parameters: + - $ref: "../parameters/page.yaml" + - $ref: "../parameters/per_page.yaml" + responses: + "200": + description: Quote versions + content: + application/json: + schema: + $ref: "../schemas/QuoteVersionsPaginated.yaml" + "401": + $ref: "../responses/Unauthorized.yaml" + "403": + $ref: "../responses/Forbidden.yaml" + "404": + $ref: "../responses/NotFound.yaml" diff --git a/src/resources/quotes.yaml b/src/resources/quotes.yaml new file mode 100644 index 00000000..bbba548e --- /dev/null +++ b/src/resources/quotes.yaml @@ -0,0 +1,105 @@ +get: + tags: + - quotes + summary: List all quotes + description: |- + This endpoint is used to list all existing quotes. + Quotes are ordered by creation date, from the most recent to the oldest. + This is a premium feature. + operationId: findAllQuotes + parameters: + - $ref: "../parameters/page.yaml" + - $ref: "../parameters/per_page.yaml" + - name: status[] + in: query + description: Filter quotes by the status of their current version. Possible values are `draft`, `approved` and `voided`. + required: false + explode: true + schema: + type: array + items: + type: string + enum: + - draft + - approved + - voided + - name: order_type[] + in: query + description: Filter quotes by order type. Possible values are `subscription_creation`, `subscription_amendment` and `one_off`. + required: false + explode: true + schema: + type: array + items: + type: string + enum: + - subscription_creation + - subscription_amendment + - one_off + - name: number[] + in: query + description: Filter quotes by their number, as assigned by Lago. + required: false + explode: true + schema: + type: array + items: + type: string + pattern: '^QT-\d{4}-\d{4,}$' + example: + - QT-2026-0001 + - QT-2026-0002 + - name: owner_id[] + in: query + description: Filter quotes by the Lago identifiers of the users owning them. + required: false + explode: true + schema: + type: array + items: + type: string + format: "uuid" + example: + - 1a901a90-1a90-1a90-1a90-1a901a901a90 + - name: external_customer_id[] + in: query + description: Filter quotes by the external unique identifiers of their customers (provided by your own application). + required: false + explode: true + schema: + type: array + items: + type: string + example: + - external_id_1234 + - name: from_date + in: query + description: Filter quotes created from a specific date. + required: false + explode: true + schema: + type: string + format: "date" + example: "2026-01-01" + - name: to_date + in: query + description: Filter quotes created up to a specific date. + required: false + explode: true + schema: + type: string + format: "date" + example: "2026-12-31" + responses: + "200": + description: Quotes + content: + application/json: + schema: + $ref: "../schemas/QuotesPaginated.yaml" + "401": + $ref: "../responses/Unauthorized.yaml" + "403": + $ref: "../responses/Forbidden.yaml" + "422": + $ref: "../responses/UnprocessableEntity.yaml" diff --git a/src/schemas/Quote.yaml b/src/schemas/Quote.yaml new file mode 100644 index 00000000..8194d62f --- /dev/null +++ b/src/schemas/Quote.yaml @@ -0,0 +1,6 @@ +type: object +required: + - quote +properties: + quote: + $ref: "./QuoteObjectExtended.yaml" diff --git a/src/schemas/QuoteBaseObject.yaml b/src/schemas/QuoteBaseObject.yaml new file mode 100644 index 00000000..0ae2b36e --- /dev/null +++ b/src/schemas/QuoteBaseObject.yaml @@ -0,0 +1,49 @@ +type: object +required: + - lago_id + - number + - order_type + - lago_customer_id + - lago_subscription_id + - lago_organization_id + - created_at + - updated_at +properties: + lago_id: + type: string + format: "uuid" + description: Unique identifier of the quote, created by Lago. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + number: + type: string + description: The unique number assigned to the quote by Lago. + example: "QT-2026-0001" + order_type: + $ref: "./QuoteOrderTypeEnum.yaml" + lago_customer_id: + type: string + format: "uuid" + description: Unique identifier of the customer the quote is addressed to, created by Lago. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + lago_subscription_id: + type: + - string + - "null" + format: "uuid" + description: Unique identifier of the subscription the quote amends, created by Lago. It is set only when the `order_type` is `subscription_amendment`. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + lago_organization_id: + type: string + format: "uuid" + description: Unique identifier of the organization, created by Lago. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + created_at: + type: string + format: "date-time" + description: The date and time in UTC (ISO 8601) when the quote was created. + example: "2026-04-29T08:59:51Z" + updated_at: + type: string + format: "date-time" + description: The date and time in UTC (ISO 8601) when the quote was last updated. + example: "2026-04-29T08:59:51Z" diff --git a/src/schemas/QuoteBillingItemAddOnObject.yaml b/src/schemas/QuoteBillingItemAddOnObject.yaml new file mode 100644 index 00000000..79d6f89b --- /dev/null +++ b/src/schemas/QuoteBillingItemAddOnObject.yaml @@ -0,0 +1,94 @@ +type: object +required: + - id + - localId + - type + - payload +properties: + id: + type: string + format: "uuid" + description: Unique identifier of the add-on in Lago, pinned when the entry was added to the quote. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + localId: + type: string + description: Identifier of the entry within the quote version, assigned by the Lago user interface. It allows the quote document to reference the entry. + example: "b5c1e2a4-4e1e-4a7f-9f0e-9c1a0c7e1f2b" + type: + type: string + description: The kind of billing item. + enum: + - add_on + example: "add_on" + payload: + type: object + description: A snapshot of the add-on as it was added to the quote. `code`, `units`, `unitAmountCents` and `totalAmountCents` are required to approve the version. + properties: + code: + type: string + description: Unique code identifying the add-on. + example: "setup_fee" + units: + type: number + description: The number of units billed. It must be greater than 0. + example: 1 + unitAmountCents: + type: integer + description: The amount of one unit, in cents, in the currency of the quote version. + example: 10000 + totalAmountCents: + type: integer + description: The total amount billed for the entry, in cents, in the currency of the quote version. + example: 10000 + fromDatetime: + type: + - string + - "null" + format: "date-time" + description: The beginning of the period covered by the entry, in UTC (ISO 8601). + example: "2026-01-01T00:00:00Z" + toDatetime: + type: + - string + - "null" + format: "date-time" + description: The end of the period covered by the entry, in UTC (ISO 8601). + example: "2026-12-31T23:59:59Z" + overrides: + type: object + description: The deviations from the add-on snapshot negotiated on the quote. Only the properties set here are overridden. + properties: + description: + type: string + description: Overrides the description of the add-on. + example: "Onboarding package, discounted for the first year" + units: + type: number + description: Overrides the number of units billed. It must be greater than 0. + example: 2 + unitAmountCents: + type: integer + description: Overrides the amount of one unit, in cents. + example: 8000 + totalAmountCents: + type: integer + description: Overrides the total amount billed for the entry, in cents. + example: 16000 + invoiceDisplayName: + type: string + description: Overrides the name of the add-on as it appears on the invoice. + example: "Onboarding" + fromDatetime: + type: + - string + - "null" + format: "date-time" + description: Overrides the beginning of the period covered by the entry, in UTC (ISO 8601). + example: "2026-01-01T00:00:00Z" + toDatetime: + type: + - string + - "null" + format: "date-time" + description: Overrides the end of the period covered by the entry, in UTC (ISO 8601). + example: "2026-12-31T23:59:59Z" diff --git a/src/schemas/QuoteBillingItemCouponObject.yaml b/src/schemas/QuoteBillingItemCouponObject.yaml new file mode 100644 index 00000000..c0166984 --- /dev/null +++ b/src/schemas/QuoteBillingItemCouponObject.yaml @@ -0,0 +1,112 @@ +type: object +required: + - id + - localId + - type + - payload +properties: + id: + type: string + format: "uuid" + description: Unique identifier of the coupon in Lago, pinned when the entry was added to the quote. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + localId: + type: string + description: Identifier of the entry within the quote version, assigned by the Lago user interface. It allows the quote document to reference the entry. + example: "b5c1e2a4-4e1e-4a7f-9f0e-9c1a0c7e1f2b" + type: + type: string + description: The kind of billing item. + enum: + - coupon + example: "coupon" + payload: + type: object + description: A snapshot of the coupon as it was added to the quote. `code` and `type` are required to approve the version. + properties: + code: + type: string + description: Unique code identifying the coupon. + example: "welcome_offer" + type: + type: string + description: Whether the coupon deducts a fixed amount or a percentage. + enum: + - fixed_amount + - percentage + example: "fixed_amount" + amountCents: + type: + - integer + - "null" + description: The amount deducted by the coupon, in cents. Only for a `fixed_amount` coupon. + example: 10000 + currency: + $ref: "./CurrencyOrNull.yaml" + description: The currency of `amountCents`. Only for a `fixed_amount` coupon. + percentageRate: + type: + - number + - "null" + description: The percentage deducted by the coupon. Only for a `percentage` coupon. It must be greater than 0. + example: 10.5 + frequency: + type: + - string + - "null" + description: How often the coupon is deducted. + enum: + - null + - once + - recurring + - forever + example: "once" + frequencyDuration: + type: + - integer + - "null" + description: The number of billing periods the coupon is deducted over. Only for a `recurring` coupon. It must be greater than 0. + example: 3 + overrides: + type: + - object + - "null" + description: The deviations from the coupon snapshot negotiated on the quote. Only the properties set here are overridden. + properties: + amountCents: + type: + - integer + - "null" + description: Overrides the amount deducted by the coupon, in cents. + example: 15000 + amountCurrency: + $ref: "./CurrencyOrNull.yaml" + description: >- + Overrides the currency the coupon is priced in, which is how a catalog + coupon is quoted in the currency of the deal. The figure in + `amountCents` is not converted, it is restated in this currency. It is + set only while it differs from the catalog record, and removed once they + agree. + percentageRate: + type: + - number + - "null" + description: Overrides the percentage deducted by the coupon. It must be greater than 0. + example: 15 + frequency: + type: + - string + - "null" + description: Overrides how often the coupon is deducted. + enum: + - null + - once + - recurring + - forever + example: "recurring" + frequencyDuration: + type: + - integer + - "null" + description: Overrides the number of billing periods the coupon is deducted over. It must be greater than 0. + example: 6 diff --git a/src/schemas/QuoteBillingItemPlanObject.yaml b/src/schemas/QuoteBillingItemPlanObject.yaml new file mode 100644 index 00000000..adce1de0 --- /dev/null +++ b/src/schemas/QuoteBillingItemPlanObject.yaml @@ -0,0 +1,311 @@ +type: object +required: + - id + - type + - payload +properties: + id: + type: string + format: "uuid" + description: Unique identifier of the plan in Lago, pinned when the entry was added to the quote. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + localId: + type: + - string + - "null" + description: Identifier of the entry within the quote version, assigned by the Lago user interface. It allows the quote document to reference the entry. + example: "b5c1e2a4-4e1e-4a7f-9f0e-9c1a0c7e1f2b" + type: + type: string + description: The kind of billing item. + enum: + - plan + example: "plan" + payload: + type: object + description: A snapshot of the plan as it was added to the quote, and of the subscription to create from it. Additional catalog properties may be present, as only the ones Lago reads when the quote is executed are documented here. `code` is required to approve the version. + properties: + code: + type: string + description: Unique code identifying the plan. + example: "premium_plan" + subscriptionExternalId: + type: + - string + - "null" + description: The external unique identifier to assign to the subscription created from the entry. For a `subscription_amendment` quote, it identifies the subscription being amended. + example: "sub_1234567890" + subscriptionName: + type: + - string + - "null" + description: The name to assign to the subscription created from the entry. + example: "Premium plan - Acme Corp" + billingTime: + type: + - string + - "null" + description: The billing time of the subscription created from the entry. + enum: + - null + - calendar + - anniversary + example: "calendar" + startDate: + type: + - string + - "null" + description: The date and time in UTC (ISO 8601) when the subscription starts. It is optional, and a plan naming none starts the moment the order is executed. + example: "2026-01-01T00:00:00Z" + endDate: + type: + - string + - "null" + description: The date and time in UTC (ISO 8601) when the subscription ends. Leaving it unset makes the deal open-ended, and on a `subscription_amendment` quote it leaves the amended subscription's own ending date in place. It bounds the deal, so the signing window and the execution date must both fall strictly before it. + example: "2027-01-01T00:00:00Z" + paymentMethodId: + type: + - string + - "null" + format: "uuid" + description: Unique identifier of the payment method to charge for the subscription, created by Lago. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + charges: + type: + - array + - "null" + description: A snapshot of the usage-based charges of the plan. It pins the charge each entry of `overrides.charges` applies to. + items: + type: object + properties: + id: + type: string + format: "uuid" + description: Unique identifier of the charge in Lago. It is required to approve the version. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + billableMetric: + type: object + description: The billable metric the charge is based on. + properties: + code: + type: string + description: Unique code identifying the billable metric. It is required to approve the version. + example: "api_calls" + chargeModel: + type: + - string + - "null" + description: The pricing model of the charge. + enum: + - null + - standard + - graduated + - graduated_percentage + - package + - percentage + - volume + - custom + - dynamic + example: "standard" + fixedCharges: + type: + - array + - "null" + description: A snapshot of the fixed charges of the plan. It pins the fixed charge each entry of `overrides.fixedCharges` applies to. + items: + type: object + properties: + id: + type: string + format: "uuid" + description: Unique identifier of the fixed charge in Lago. It is required to approve the version. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + addOn: + type: object + description: The add-on the fixed charge is based on. + properties: + code: + type: string + description: Unique code identifying the add-on. It is required to approve the version. + example: "seats" + chargeModel: + type: + - string + - "null" + description: The pricing model of the fixed charge. + enum: + - null + - standard + - graduated + - volume + example: "standard" + overrides: + type: + - object + - "null" + description: The deviations from the plan snapshot negotiated on the quote. Only the properties set here are overridden. + properties: + amountCents: + type: + - integer + - "null" + description: Overrides the base amount of the plan, in cents. + example: 50000 + amountCurrency: + $ref: "./CurrencyOrNull.yaml" + description: >- + Overrides the currency the plan is priced in, which is how a catalog + plan is quoted in the currency of the deal. The figure in + `amountCents` is not converted, it is restated in this currency. It is + set only while it differs from the catalog record, and removed once they + agree. + invoiceDisplayName: + type: + - string + - "null" + description: Overrides the name of the plan as it appears on the invoice. + example: "Premium" + name: + type: + - string + - "null" + description: Overrides the name of the plan. + example: "Premium plan - Acme Corp" + description: + type: + - string + - "null" + description: Overrides the description of the plan. + example: "Negotiated premium plan" + trialPeriod: + type: + - number + - "null" + description: Overrides the trial period of the plan, in days. + example: 30 + minimumCommitment: + type: + - object + - "null" + description: Overrides the minimum commitment of the plan. + properties: + amountCents: + type: + - integer + - "null" + description: The amount of the minimum commitment, in cents. It must be greater than 0. + example: 100000 + invoiceDisplayName: + type: + - string + - "null" + description: The name of the minimum commitment as it appears on the invoice. + example: "Annual commitment" + usageThresholds: + type: + - array + - "null" + description: Overrides the progressive billing thresholds of the plan. + items: + type: object + required: + - amountCents + properties: + amountCents: + type: integer + description: The usage amount, in cents, at which the threshold is reached. It must be greater than 0. + example: 100000 + recurring: + type: + - boolean + - "null" + description: Whether the threshold applies to every period, instead of only once. + example: false + thresholdDisplayName: + type: + - string + - "null" + description: The name of the threshold as it appears on the invoice. + example: "First 1,000 EUR of usage" + charges: + type: + - array + - "null" + description: Overrides the usage-based charges of the plan. Each entry applies to the charge of the same billable metric in `payload.charges`. + items: + type: object + required: + - billableMetricCode + properties: + billableMetricCode: + type: string + description: Unique code identifying the billable metric of the charge to override. + example: "api_calls" + chargeModel: + type: + - string + - "null" + description: The pricing model of the charge. + enum: + - null + - standard + - graduated + - graduated_percentage + - package + - percentage + - volume + - custom + - dynamic + example: "standard" + properties: + type: + - object + - "null" + description: The pricing properties of the charge. Their shape depends on the charge model, and is validated when the quote is executed. + example: + amount: "0.02" + minAmountCents: + type: + - integer + - "null" + description: The minimum amount billed for the charge, in cents. + example: 10000 + invoiceDisplayName: + type: + - string + - "null" + description: The name of the charge as it appears on the invoice. + example: "API calls" + fixedCharges: + type: + - array + - "null" + description: Overrides the fixed charges of the plan. Each entry applies to the fixed charge of the same add-on in `payload.fixedCharges`. + items: + type: object + required: + - addOnCode + properties: + addOnCode: + type: string + description: Unique code identifying the add-on of the fixed charge to override. + example: "seats" + units: + type: + - string + - "null" + description: The number of units billed by the fixed charge. + example: "10" + properties: + type: + - object + - "null" + description: The pricing properties of the fixed charge. Their shape depends on the charge model, and is validated when the quote is executed. + example: + amount: "5" + invoiceDisplayName: + type: + - string + - "null" + description: The name of the fixed charge as it appears on the invoice. + example: "Seats" diff --git a/src/schemas/QuoteBillingItemWalletCreditObject.yaml b/src/schemas/QuoteBillingItemWalletCreditObject.yaml new file mode 100644 index 00000000..7e4af4f8 --- /dev/null +++ b/src/schemas/QuoteBillingItemWalletCreditObject.yaml @@ -0,0 +1,175 @@ +type: object +required: + - localId + - type + - payload +properties: + localId: + type: string + description: Identifier of the entry within the quote version, assigned by the Lago user interface. It allows the quote document to reference the entry. + example: "b5c1e2a4-4e1e-4a7f-9f0e-9c1a0c7e1f2b" + type: + type: string + description: The kind of billing item. + enum: + - wallet_credit + example: "wallet_credit" + payload: + type: object + description: The prepaid credit wallet to create for the customer. Unlike the other billing items, a wallet credit is not built from an existing record, so it carries no `id` and no `overrides`. `paidCredits`, `grantedCredits` and `rateAmount` are required to approve the version. + properties: + paidCredits: + type: + - string + - "null" + description: The number of credits the customer pays for. + example: "100.0" + grantedCredits: + type: + - string + - "null" + description: The number of credits granted for free. + example: "20.0" + rateAmount: + type: + - string + - "null" + description: The value of one credit, in the currency of the wallet. + example: "1.0" + currency: + $ref: "./CurrencyOrNull.yaml" + description: The currency of the wallet. + expirationAt: + type: + - string + - "null" + format: "date-time" + description: The date and time in UTC (ISO 8601) when the credits expire. + example: "2027-01-01T00:00:00Z" + appliesTo: + type: + - object + - "null" + description: The limitations restricting what the credits can be spent on. + properties: + feeTypes: + type: + - array + - "null" + description: The fee types the credits can be spent on. + items: + type: string + enum: + - charge + - add_on + - subscription + - credit + - commitment + - fixed_charge + - product + example: ["charge"] + billableMetricCodes: + type: + - array + - "null" + description: The codes of the billable metrics the credits can be spent on. + items: + type: string + example: ["api_calls"] + recurringTransactionRules: + type: + - array + - "null" + description: The rule automatically topping the wallet up. At most one rule is allowed, and its `trigger` is required, to approve the version. + items: + type: object + properties: + trigger: + type: + - string + - "null" + description: What triggers the top-up. + enum: + - null + - interval + - threshold + example: "interval" + interval: + type: + - string + - "null" + description: How often the wallet is topped up. Only for an `interval` trigger. + enum: + - null + - weekly + - monthly + - quarterly + - semiannual + - yearly + example: "monthly" + thresholdCredits: + type: + - string + - "null" + description: The credit balance below which the wallet is topped up. Only for a `threshold` trigger. + example: "10.0" + method: + type: + - string + - "null" + description: Whether the top-up grants a fixed number of credits, or brings the balance up to a target. + enum: + - null + - fixed + - target + example: "fixed" + targetOngoingBalance: + type: + - string + - "null" + description: The balance the top-up brings the wallet up to. Only for a `target` method. + example: "100.0" + grantsTargetTopUp: + type: + - boolean + - "null" + description: Whether the granted credits count towards the target balance. + example: false + paidCredits: + type: + - string + - "null" + description: The number of credits the customer pays for on every top-up. + example: "100.0" + grantedCredits: + type: + - string + - "null" + description: The number of credits granted for free on every top-up. + example: "20.0" + startedAt: + type: + - string + - "null" + format: "date-time" + description: The date and time in UTC (ISO 8601) when the rule starts applying. + example: "2026-01-01T00:00:00Z" + expirationAt: + type: + - string + - "null" + format: "date-time" + description: The date and time in UTC (ISO 8601) when the rule stops applying. + example: "2027-01-01T00:00:00Z" + transactionName: + type: + - string + - "null" + description: The name given to the wallet transactions created by the rule. + example: "Monthly top-up" + invoiceRequiresSuccessfulPayment: + type: + - boolean + - "null" + description: Whether the credits are granted only once the top-up invoice is paid. + example: false diff --git a/src/schemas/QuoteBillingItems.yaml b/src/schemas/QuoteBillingItems.yaml new file mode 100644 index 00000000..092fa0ed --- /dev/null +++ b/src/schemas/QuoteBillingItems.yaml @@ -0,0 +1,36 @@ +type: + - object + - "null" +description: | + A snapshot of everything the quote bills. Unlike the rest of the Lago API, the keys nested in this object are camelCased: the object is stored and returned as it is authored in the Lago user interface. + + Which top-level keys are present depends on the `order_type` of the parent quote: + - `one_off`: `addOns`. + - `subscription_creation` and `subscription_amendment`: `plans`, plus the optional `coupons` and `walletCredits`. + + Every entry pins the catalog record it was built from through its `id` and its `payload`, so that an approved quote keeps billing what was approved even if the catalog changes afterwards. The optional `overrides` object carries the deviations from that record negotiated on the quote. + + This object is the single source of truth for the term of the deal. Three of its nested dates bound that term, because the execution flow refuses them once past: `plans[].payload.endDate`, `walletCredits[].payload.expirationAt` and the `expirationAt` of a wallet credit's recurring top-up rule. The earliest of them is the day the deal stops being executable, and both the signing window and the execution date must fall strictly before it. A `one_off` quote carries none of them and is never bounded. + + On a `draft` version this object may be incomplete: only the properties documented as required below are enforced on every save, the others are enforced when the version is approved. +properties: + addOns: + type: array + description: The add-ons billed once by a `one_off` quote. At least one entry is required to approve the version. + items: + $ref: "./QuoteBillingItemAddOnObject.yaml" + plans: + type: array + description: The plans subscribed to, or amended, by a `subscription_creation` or `subscription_amendment` quote. At least one entry is required to approve the version. + items: + $ref: "./QuoteBillingItemPlanObject.yaml" + coupons: + type: array + description: The coupons applied to the customer when the quote is executed. + items: + $ref: "./QuoteBillingItemCouponObject.yaml" + walletCredits: + type: array + description: The prepaid credit wallets created for the customer when the quote is executed. + items: + $ref: "./QuoteBillingItemWalletCreditObject.yaml" diff --git a/src/schemas/QuoteObject.yaml b/src/schemas/QuoteObject.yaml new file mode 100644 index 00000000..d0e041e4 --- /dev/null +++ b/src/schemas/QuoteObject.yaml @@ -0,0 +1,11 @@ +allOf: + - $ref: "./QuoteBaseObject.yaml" + - type: object + required: + - current_version + properties: + current_version: + oneOf: + - $ref: "./QuoteVersionObject.yaml" + - type: "null" + description: The latest version of the quote. Its `content` and `billing_items` are omitted here; retrieve the version to get them. diff --git a/src/schemas/QuoteObjectExtended.yaml b/src/schemas/QuoteObjectExtended.yaml new file mode 100644 index 00000000..4ddaa83f --- /dev/null +++ b/src/schemas/QuoteObjectExtended.yaml @@ -0,0 +1,11 @@ +allOf: + - $ref: "./QuoteObject.yaml" + - type: object + required: + - owners + properties: + owners: + type: array + description: The users of the organization responsible for the quote. + items: + $ref: "./QuoteOwnerObject.yaml" diff --git a/src/schemas/QuoteOrderTypeEnum.yaml b/src/schemas/QuoteOrderTypeEnum.yaml new file mode 100644 index 00000000..d98fcda6 --- /dev/null +++ b/src/schemas/QuoteOrderTypeEnum.yaml @@ -0,0 +1,11 @@ +type: string +description: | + The commercial motion the quote describes. It can be any of the following values: + - `subscription_creation`: the quote creates one or more subscriptions. + - `subscription_amendment`: the quote amends an existing subscription, named by the quote's own `lago_subscription_id`. + - `one_off`: the quote bills add-ons once, without any subscription. +enum: + - subscription_creation + - subscription_amendment + - one_off +example: "subscription_creation" diff --git a/src/schemas/QuoteOwnerObject.yaml b/src/schemas/QuoteOwnerObject.yaml new file mode 100644 index 00000000..764bd8c5 --- /dev/null +++ b/src/schemas/QuoteOwnerObject.yaml @@ -0,0 +1,17 @@ +type: object +required: + - lago_id + - email +properties: + lago_id: + type: string + format: "uuid" + description: Unique identifier of the user owning the quote, created by Lago. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + email: + type: + - string + - "null" + format: "email" + description: The email address of the user owning the quote. + example: "sales@getlago.com" diff --git a/src/schemas/QuoteVersion.yaml b/src/schemas/QuoteVersion.yaml new file mode 100644 index 00000000..aa56764b --- /dev/null +++ b/src/schemas/QuoteVersion.yaml @@ -0,0 +1,6 @@ +type: object +required: + - quote_version +properties: + quote_version: + $ref: "./QuoteVersionObjectExtended.yaml" diff --git a/src/schemas/QuoteVersionApproveInput.yaml b/src/schemas/QuoteVersionApproveInput.yaml new file mode 100644 index 00000000..7b6d9bc5 --- /dev/null +++ b/src/schemas/QuoteVersionApproveInput.yaml @@ -0,0 +1,16 @@ +type: object +description: Parameters available when approving a quote version. +required: [] +properties: + expires_at: + type: string + format: "date-time" + description: >- + The date and time in UTC (ISO 8601) when the order form generated by the + approval expires. It must be in the future, and must fall strictly before + the day the quoted deal stops being executable, otherwise the approval is + rejected with a `422`. That boundary is the earliest of the `endDate` of any + quoted plan and the `expirationAt` of any quoted wallet credit or recurring + top-up rule. A `one_off` quote carries none of them, so its signing window is + never bounded. When `expires_at` is omitted, the order form never expires. + example: "2026-06-30T23:59:59Z" diff --git a/src/schemas/QuoteVersionObject.yaml b/src/schemas/QuoteVersionObject.yaml new file mode 100644 index 00000000..1203ca8a --- /dev/null +++ b/src/schemas/QuoteVersionObject.yaml @@ -0,0 +1,77 @@ +type: object +required: + - lago_id + - lago_quote_id + - lago_organization_id + - version + - status + - currency + - billing_entity_code + - void_reason + - approved_at + - voided_at + - created_at + - updated_at +properties: + lago_id: + type: string + format: "uuid" + description: Unique identifier of the quote version, created by Lago. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + lago_quote_id: + type: string + format: "uuid" + description: Unique identifier of the quote the version belongs to, created by Lago. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + lago_organization_id: + type: string + format: "uuid" + description: Unique identifier of the organization, created by Lago. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + version: + type: integer + description: The number of the version within the quote. It starts at 1 and increases by 1 for every new version created by cloning. + example: 1 + status: + $ref: "./QuoteVersionStatusEnum.yaml" + currency: + $ref: "./CurrencyOrNull.yaml" + description: The currency the version is quoted in. + billing_entity_code: + type: + - string + - "null" + description: >- + Unique code identifying the billing entity that issues the deal. It is + resolved rather than stored: the version's own entity when it names one, then + the entity of the subscription being amended for a `subscription_amendment` + quote, then the customer's own. It is `null` when none of them resolves. An + amendment cannot name an entity itself, since the subscription it restates is + already bound to one, and naming one on an amendment is rejected. + example: "acme_corp" + void_reason: + $ref: "./QuoteVersionVoidReasonEnum.yaml" + approved_at: + type: + - string + - "null" + format: "date-time" + description: The date and time in UTC (ISO 8601) when the version was approved. It is `null` unless the `status` is `approved`. + example: "2026-04-29T08:59:51Z" + voided_at: + type: + - string + - "null" + format: "date-time" + description: The date and time in UTC (ISO 8601) when the version was voided. It is `null` unless the `status` is `voided`. + example: "2026-04-29T08:59:51Z" + created_at: + type: string + format: "date-time" + description: The date and time in UTC (ISO 8601) when the version was created. + example: "2026-04-29T08:59:51Z" + updated_at: + type: string + format: "date-time" + description: The date and time in UTC (ISO 8601) when the version was last updated. + example: "2026-04-29T08:59:51Z" diff --git a/src/schemas/QuoteVersionObjectExtended.yaml b/src/schemas/QuoteVersionObjectExtended.yaml new file mode 100644 index 00000000..3bf10bd3 --- /dev/null +++ b/src/schemas/QuoteVersionObjectExtended.yaml @@ -0,0 +1,15 @@ +allOf: + - $ref: "./QuoteVersionObject.yaml" + - type: object + required: + - content + - billing_items + properties: + content: + type: + - string + - "null" + description: The HTML body of the quote document, as authored in the Lago user interface. It may reference the entries of `billing_items` through their `localId`. + example: "

Quote QT-2026-0001

Prepared for Acme Corp.

" + billing_items: + $ref: "./QuoteBillingItems.yaml" diff --git a/src/schemas/QuoteVersionStatusEnum.yaml b/src/schemas/QuoteVersionStatusEnum.yaml new file mode 100644 index 00000000..2f308258 --- /dev/null +++ b/src/schemas/QuoteVersionStatusEnum.yaml @@ -0,0 +1,13 @@ +type: string +description: | + The status of the quote version. It can be any of the following values: + - `draft`: the version is still editable. + - `approved`: the version has been approved and an order form has been generated from it. + - `voided`: the version is no longer actionable. + + A quote has at most one version in `draft` or `approved` status at any time; all the other versions are `voided`. +enum: + - draft + - approved + - voided +example: "draft" diff --git a/src/schemas/QuoteVersionVoidReasonEnum.yaml b/src/schemas/QuoteVersionVoidReasonEnum.yaml new file mode 100644 index 00000000..a7aa7054 --- /dev/null +++ b/src/schemas/QuoteVersionVoidReasonEnum.yaml @@ -0,0 +1,16 @@ +type: + - string + - "null" +description: | + The reason why the quote version was voided. It is `null` unless the `status` is `voided`. It can be any of the following values: + - `manual`: voided explicitly, through the API or the Lago user interface. + - `superseded`: voided because the version was cloned into a new draft. + - `cascade_of_expired`: voided because the order form generated from the version expired. + - `cascade_of_voided`: voided because the order form generated from the version was voided. +enum: + - null + - manual + - superseded + - cascade_of_expired + - cascade_of_voided +example: "manual" diff --git a/src/schemas/QuoteVersionsPaginated.yaml b/src/schemas/QuoteVersionsPaginated.yaml new file mode 100644 index 00000000..0a1a110c --- /dev/null +++ b/src/schemas/QuoteVersionsPaginated.yaml @@ -0,0 +1,11 @@ +type: object +required: + - quote_versions + - meta +properties: + quote_versions: + type: array + items: + $ref: "./QuoteVersionObject.yaml" + meta: + $ref: "./PaginationMeta.yaml" diff --git a/src/schemas/QuoteWithVersionObject.yaml b/src/schemas/QuoteWithVersionObject.yaml new file mode 100644 index 00000000..6fce42ec --- /dev/null +++ b/src/schemas/QuoteWithVersionObject.yaml @@ -0,0 +1,14 @@ +allOf: + - $ref: "./QuoteBaseObject.yaml" + - type: object + required: + - version + properties: + version: + $ref: "./QuoteVersionObject.yaml" + description: >- + The version of the quote the event happened to. It is not necessarily + the current version of the quote, as a `quote.voided` event triggered + by a clone names the version that was voided while the quote already + carries its replacement. Its `content` and `billing_items` are omitted + here; retrieve the version to get them. diff --git a/src/schemas/QuotesPaginated.yaml b/src/schemas/QuotesPaginated.yaml new file mode 100644 index 00000000..1b0928a8 --- /dev/null +++ b/src/schemas/QuotesPaginated.yaml @@ -0,0 +1,11 @@ +type: object +required: + - quotes + - meta +properties: + quotes: + type: array + items: + $ref: "./QuoteObject.yaml" + meta: + $ref: "./PaginationMeta.yaml" diff --git a/src/webhooks/quote_approved.yaml b/src/webhooks/quote_approved.yaml new file mode 100644 index 00000000..ed6d3161 --- /dev/null +++ b/src/webhooks/quote_approved.yaml @@ -0,0 +1,40 @@ +post: + operationId: quoteApproved + summary: A quote has been approved + description: |- + A version of a quote has been approved. An order form is generated from it in the same transaction, so an `order_form.created` event follows. + This is a premium feature. + parameters: + - $ref: "../parameters/webhook_signature.yaml" + - $ref: "../parameters/webhook_signature_algorithm.yaml" + - $ref: "../parameters/webhook_unique_key.yaml" + requestBody: + description: Details of the approved quote + content: + application/json: + schema: + type: object + required: + - webhook_type + - object_type + - organization_id + - quote + properties: + webhook_type: + type: string + enum: + - quote.approved + object_type: + type: string + enum: + - quote + organization_id: + type: string + format: "uuid" + description: Unique identifier of the organization, created by Lago. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + quote: + $ref: "../schemas/QuoteWithVersionObject.yaml" + responses: + "200": + description: Return a 200 status to indicate that the data was received successfully diff --git a/src/webhooks/quote_created.yaml b/src/webhooks/quote_created.yaml new file mode 100644 index 00000000..c135a373 --- /dev/null +++ b/src/webhooks/quote_created.yaml @@ -0,0 +1,40 @@ +post: + operationId: quoteCreated + summary: A new quote has been created + description: |- + A new quote has been created. The payload names the initial `draft` version of the quote, numbered 1. + This is a premium feature. + parameters: + - $ref: "../parameters/webhook_signature.yaml" + - $ref: "../parameters/webhook_signature_algorithm.yaml" + - $ref: "../parameters/webhook_unique_key.yaml" + requestBody: + description: Details of the new quote + content: + application/json: + schema: + type: object + required: + - webhook_type + - object_type + - organization_id + - quote + properties: + webhook_type: + type: string + enum: + - quote.created + object_type: + type: string + enum: + - quote + organization_id: + type: string + format: "uuid" + description: Unique identifier of the organization, created by Lago. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + quote: + $ref: "../schemas/QuoteWithVersionObject.yaml" + responses: + "200": + description: Return a 200 status to indicate that the data was received successfully diff --git a/src/webhooks/quote_voided.yaml b/src/webhooks/quote_voided.yaml new file mode 100644 index 00000000..8fc2b549 --- /dev/null +++ b/src/webhooks/quote_voided.yaml @@ -0,0 +1,40 @@ +post: + operationId: quoteVoided + summary: A quote has been voided + description: |- + A version of a quote has been voided. It is emitted whichever way the version was voided, so read `version.void_reason` to tell them apart: `manual` for an explicit void, `superseded` when the version was cloned into a new draft, `cascade_of_expired` or `cascade_of_voided` when the order form generated from it expired or was voided. + This is a premium feature. + parameters: + - $ref: "../parameters/webhook_signature.yaml" + - $ref: "../parameters/webhook_signature_algorithm.yaml" + - $ref: "../parameters/webhook_unique_key.yaml" + requestBody: + description: Details of the voided quote + content: + application/json: + schema: + type: object + required: + - webhook_type + - object_type + - organization_id + - quote + properties: + webhook_type: + type: string + enum: + - quote.voided + object_type: + type: string + enum: + - quote + organization_id: + type: string + format: "uuid" + description: Unique identifier of the organization, created by Lago. + example: "1a901a90-1a90-1a90-1a90-1a901a901a90" + quote: + $ref: "../schemas/QuoteWithVersionObject.yaml" + responses: + "200": + description: Return a 200 status to indicate that the data was received successfully