Quotes

Priced offers built from lines — from your product catalogue or free text — with VAT on each line, an optional quote-level discount and an optional ROT/RUT estimate. A sent quote gets its own link (share_url) where the buyer can accept or reject it without a deal room; a quote placed in a deal room can also be answered by the room's stakeholders.

Totals are always computed by Closepact, in öre, by the same rules as an invoice. Every amount is rounded half up exactly once per line, and totals are sums of the rounded lines:

  • a line's line_total_cents is quantity × unit_price_cents less the line's discount_percent; quantity may have up to three decimals (2.5 hours);
  • its net_cents additionally carries the quote's discount_percent (10 % on a line already 25 % off is 32.5 % off), and its vat_cents is vat_rate of that net — 25, 12, 6 or 0, inherited from the product unless you set it;
  • subtotal_cents is the sum of line totals, discount_cents what the quote discount took off them, tax_cents the sum of line VAT, and total_cents net plus VAT; vat_breakdown gives net and VAT per rate.

Only lines that count are summed: every fixed line, and an optional line (is_optional) only while is_selected. The buyer ticks optional lines in or out when accepting.

rot_rut estimates a ROT (30 %) or RUT (50 %) deduction on the labour lines including VAT — materials never qualify — and what the buyer pays after it. It is preliminary: the yearly ceiling per person is not applied.

Creating and changing quotes is included from the Väx tier of proposals (proposals.cpq); on Start those operations answer 402 and existing quotes stay readable.

An accepted quote is handed over — to a work order waiting to be planned when you have the scheduling module, otherwise to an invoice draft when you have invoicing — automatically on acceptance or with Hand over an accepted quote, as each quote's handover says. That is included from the Väx tier of proposals (proposals.convert).

List quotes

GET/quotes

Returns the organization's quotes, newest first, each with its lines, as a cursor-paginated list. Page through with cursor until meta.next_cursor is null; links.next keeps your filters.

curl 'https://api.closepact.com/v1/api/quotes' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "01a15c50-8d9e-7f0a-b1c2-d3e4f5a6b7c8",
      "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
      "deal_room_id": "01a15c40-1f2e-7d9a-8b3c-4e5f6a7b8c9d",
      "quote_number": "Q-00042",
      "title": "Offert hemstädning – familjen Ny",
      "status": "sent",
      "subtotal_cents": 320000,
      "discount_cents": 0,
      "discount_percent": 0,
      "tax_cents": 80000,
      "tax_percent": 25,
      "total_cents": 400000,
      "vat_breakdown": [
        {
          "rate": 25,
          "base_cents": 320000,
          "vat_cents": 80000
        }
      ],
      "rot_rut": {
        "type": "rut",
        "rate_percent": 50,
        "labour_cents": 400000,
        "deduction_cents": 200000,
        "customer_pays_cents": 200000,
        "preliminary": true,
        "annual_ceiling_applied": false
      },
      "currency": "SEK",
      "expires_at": "2026-11-17",
      "accepted_at": null,
      "accepted_by_stakeholder_id": null,
      "acceptance": null,
      "rejection_reason": null,
      "share_url": "https://app.closepact.com/q/k3Jq8vR2mXw9TzL5pN7cH4bY6sD1fG0aE8uQ3iO5rV2tW9xZ",
      "handover": {
        "available": true,
        "target": "work_order",
        "mode": "automatic",
        "work_order": null,
        "invoice": null,
        "blocked_reason": null
      },
      "lines": [
        {
          "id": "01a15c52-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
          "product_id": "01a15b70-6c7d-7e8f-9a0b-1c2d3e4f5a6b",
          "name": "Hemstäd varannan vecka",
          "description": "Två timmar per tillfälle, RUT-avdrag tillämpas på fakturan.",
          "quantity": 2,
          "unit_price_cents": 160000,
          "discount_percent": 0,
          "vat_rate": 25,
          "line_total_cents": 320000,
          "net_cents": 320000,
          "vat_cents": 80000,
          "line_type": "labour",
          "is_optional": false,
          "is_selected": true,
          "billing_cycle": "monthly",
          "position": 0
        }
      ],
      "created_at": "2026-10-13T08:30:00+00:00",
      "updated_at": "2026-10-13T09:05:12+00:00"
    }
  ],
  "links": {
    "first": null,
    "last": null,
    "prev": null,
    "next": null
  },
  "meta": {
    "path": "https://api.closepact.com/v1/api/quotes",
    "per_page": 25,
    "next_cursor": null,
    "prev_cursor": null
  }
}

Query parameters

  • deal_idstring(uuid)

    Only quotes for this deal.

  • deal_room_idstring(uuid)

    Only quotes placed in this room.

  • statusstring

    Only quotes with this status.

    One ofdraftsentacceptedrejectedexpired

  • limitinteger

    Items per page. Values outside 1–100 are clamped.

    Default 251–100

  • cursorstring

    Opaque cursor from meta.next_cursor or meta.prev_cursor of the previous page.

Responses

  • Headers

    • X-RateLimit-Limit — Requests this key may make per minute.
    • X-RateLimit-Remaining — Requests left in the current minute.
    • dataarray of objectsrequired
      • idstring(uuid)required
      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired

        The room whose stakeholders can accept the quote.

      • quote_numberstringrequired

        Sequential within the organization.

        Example "Q-00042"

      • titlestringrequired
      • statusstringrequired

        draft until sent, and the only state whose lines and terms can change; sent once in front of the buyer, who can accept or reject it until the end of its expires_at day; accepted or rejected by the buyer, after which it never changes; expired when a sent quote's last day passed unanswered (set by an hourly sweep). A sent or expired quote goes back to draft only through Revert to draft.

        One ofdraftsentacceptedrejectedexpired

      • subtotal_centsintegerrequired

        Sum of the totals of the lines that count, in öre, before the quote discount and VAT.

      • discount_centsintegerrequired

        What the quote's discount_percent took off those lines, in öre.

      • discount_percentintegerrequired

        0–100

      • tax_centsintegerrequired

        The VAT of the lines that count, summed — each line's rounded once. Per rate in vat_breakdown.

      • tax_percentintegerrequireddeprecated

        Deprecated: VAT is per line (lines[].vat_rate, vat_breakdown). Kept for older integrations: it reads as the rate every counted line shares, and is left as it was when the rates are mixed. It never changes an amount.

        0–100

      • total_centsintegerrequired

        What the quote comes to, VAT included, in öre: 400000 is 4 000 kr. Before any ROT/RUT deduction — see rot_rut.customer_pays_cents.

      • vat_breakdownarray of objectsrequired

        Net and VAT per rate over the lines that count, highest rate first — as an invoice has to state them.

      • rot_rutobjectrequired

        A preliminary ROT/RUT estimate, kept apart from the total. The yearly ceiling per person is not applied — it depends on what other companies have already claimed — and Skatteverket decides after the invoice.

      • currencystringrequired

        exactly 3 characters

      • expires_atstring(date)nullablerequired

        Last day the quote can be accepted (inclusive).

      • accepted_atstring(date-time)nullablerequired
      • accepted_by_stakeholder_idstring(uuid)nullablerequired

        The room stakeholder who accepted it, when it was accepted in a room.

      • acceptanceobjectnullablerequired

        What the buyer agreed to, recorded once at the moment of acceptance. Null until accepted, and on quotes accepted before this was recorded.

      • rejection_reasonstringnullablerequired

        What the buyer wrote when rejecting it.

      • share_urlstring(uri)nullablerequired

        The quote's own page, where the buyer can read it, tick options and accept or reject it without a deal room. Issued when the quote is sent, revoked when it is reverted to draft (a new one comes with the next send). Null on a draft. Anyone holding it can answer the quote, so share it only with the buyer.

      • handoverobjectrequired

        What an accepted quote becomes in your organization, and what it became. With the scheduling module it becomes a work order waiting to be planned; with invoicing and no scheduling, an invoice draft. available, target and mode describe your organization and are the same on every quote; work_order, invoice and blocked_reason describe this one. See Hand over an accepted quote.

      • linesarray of objectsrequired
      • created_atstring(date-time)required
      • updated_atstring(date-time)required
    • linksobjectrequired
    • metaobjectrequired
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (module_seat_required — an administrator assigns seats under Settings → Users), or the organization is suspended.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Create a quote

POST/quotes
Scope write Module Proposals & e-signing Permission cpq.quotes.create

Creates an empty draft quote with the next number in the organization's series (Q-00001, Q-00002, …), then add lines with Add a line. Place it in a room with deal_room_id so the room's stakeholders can accept it once it is sent.

Not idempotent: each call creates another quote and uses up a number.

curl -X POST 'https://api.closepact.com/v1/api/quotes' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Offert hemstädning – familjen Ny",
  "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
  "deal_room_id": "01a15c40-1f2e-7d9a-8b3c-4e5f6a7b8c9d",
  "rot_rut": "rut",
  "expires_at": "2026-11-17"
}'
Response · 201
{
  "data": {
    "id": "01a15c50-8d9e-7f0a-b1c2-d3e4f5a6b7c8",
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": "01a15c40-1f2e-7d9a-8b3c-4e5f6a7b8c9d",
    "quote_number": "Q-00042",
    "title": "Offert hemstädning – familjen Ny",
    "status": "draft",
    "subtotal_cents": 0,
    "discount_cents": 0,
    "discount_percent": 0,
    "tax_cents": 0,
    "tax_percent": 0,
    "total_cents": 0,
    "vat_breakdown": [],
    "rot_rut": {
      "type": "rut",
      "rate_percent": 50,
      "labour_cents": 0,
      "deduction_cents": 0,
      "customer_pays_cents": 0,
      "preliminary": true,
      "annual_ceiling_applied": false
    },
    "currency": "SEK",
    "expires_at": "2026-11-17",
    "accepted_at": null,
    "accepted_by_stakeholder_id": null,
    "acceptance": null,
    "rejection_reason": null,
    "share_url": null,
    "handover": {
      "available": true,
      "target": "work_order",
      "mode": "automatic",
      "work_order": null,
      "invoice": null,
      "blocked_reason": null
    },
    "lines": [],
    "created_at": "2026-10-13T08:30:00+00:00",
    "updated_at": "2026-10-13T08:30:00+00:00"
  }
}

Request body

application/json · required

  • titlestringrequired

    at most 255 characters

  • deal_idstring(uuid)nullable

    A deal in this organization.

  • deal_room_idstring(uuid)nullable

    A room in this organization, whose stakeholders will see the quote once it is sent.

  • currencystringnullable

    ISO 4217 code, upper case. Stored as sent.

    Default "SEK"exactly 3 characters

  • discount_percentintegernullable

    Discount on the whole quote, in whole percent. Applied to each line before its VAT.

    Default 00–100

  • rot_rutstringnullable

    The tax deduction to estimate on the quote's labour lines: rot (30 %), rut (50 %) or none.

    One ofnonerotrut

    Default "none"

  • tax_percentintegernullabledeprecated

    Deprecated: VAT is set per line (vat_rate on each line). Still accepted so older integrations keep working, but it changes no amount.

    0–100

  • expires_atstring(date)nullable

    Last day the quote can be accepted. Must be after today.

Responses

  • Headers

    • X-RateLimit-Limit — Requests this key may make per minute.
    • X-RateLimit-Remaining — Requests left in the current minute.
    • dataobjectrequired
      • idstring(uuid)required
      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired

        The room whose stakeholders can accept the quote.

      • quote_numberstringrequired

        Sequential within the organization.

        Example "Q-00042"

      • titlestringrequired
      • statusstringrequired

        draft until sent, and the only state whose lines and terms can change; sent once in front of the buyer, who can accept or reject it until the end of its expires_at day; accepted or rejected by the buyer, after which it never changes; expired when a sent quote's last day passed unanswered (set by an hourly sweep). A sent or expired quote goes back to draft only through Revert to draft.

        One ofdraftsentacceptedrejectedexpired

      • subtotal_centsintegerrequired

        Sum of the totals of the lines that count, in öre, before the quote discount and VAT.

      • discount_centsintegerrequired

        What the quote's discount_percent took off those lines, in öre.

      • discount_percentintegerrequired

        0–100

      • tax_centsintegerrequired

        The VAT of the lines that count, summed — each line's rounded once. Per rate in vat_breakdown.

      • tax_percentintegerrequireddeprecated

        Deprecated: VAT is per line (lines[].vat_rate, vat_breakdown). Kept for older integrations: it reads as the rate every counted line shares, and is left as it was when the rates are mixed. It never changes an amount.

        0–100

      • total_centsintegerrequired

        What the quote comes to, VAT included, in öre: 400000 is 4 000 kr. Before any ROT/RUT deduction — see rot_rut.customer_pays_cents.

      • vat_breakdownarray of objectsrequired

        Net and VAT per rate over the lines that count, highest rate first — as an invoice has to state them.

      • rot_rutobjectrequired

        A preliminary ROT/RUT estimate, kept apart from the total. The yearly ceiling per person is not applied — it depends on what other companies have already claimed — and Skatteverket decides after the invoice.

      • currencystringrequired

        exactly 3 characters

      • expires_atstring(date)nullablerequired

        Last day the quote can be accepted (inclusive).

      • accepted_atstring(date-time)nullablerequired
      • accepted_by_stakeholder_idstring(uuid)nullablerequired

        The room stakeholder who accepted it, when it was accepted in a room.

      • acceptanceobjectnullablerequired

        What the buyer agreed to, recorded once at the moment of acceptance. Null until accepted, and on quotes accepted before this was recorded.

      • rejection_reasonstringnullablerequired

        What the buyer wrote when rejecting it.

      • share_urlstring(uri)nullablerequired

        The quote's own page, where the buyer can read it, tick options and accept or reject it without a deal room. Issued when the quote is sent, revoked when it is reverted to draft (a new one comes with the next send). Null on a draft. Anyone holding it can answer the quote, so share it only with the buyer.

      • handoverobjectrequired

        What an accepted quote becomes in your organization, and what it became. With the scheduling module it becomes a work order waiting to be planned; with invoicing and no scheduling, an invoice draft. available, target and mode describe your organization and are the same on every quote; work_order, invoice and blocked_reason describe this one. See Hand over an accepted quote.

      • linesarray of objectsrequired
      • created_atstring(date-time)required
      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (module_seat_required — an administrator assigns seats under Settings → Users), or the organization is suspended.
    Errors
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Retrieve a quote

GET/quotes/{quote}

Returns one quote with its lines in order. Poll this (or listen for the quote.accepted webhook) to learn whether the buyer accepted or rejected it: status, accepted_at, acceptance and rejection_reason say so. Once accepted, acceptance records who accepted, through which door, the optional lines they ticked and the totals at that moment; the lines' is_selected and the quote's totals reflect the same choice.

curl 'https://api.closepact.com/v1/api/quotes/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 200
{
  "data": {
    "id": "01a15c50-8d9e-7f0a-b1c2-d3e4f5a6b7c8",
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": "01a15c40-1f2e-7d9a-8b3c-4e5f6a7b8c9d",
    "quote_number": "Q-00042",
    "title": "Offert hemstädning – familjen Ny",
    "status": "accepted",
    "subtotal_cents": 387500,
    "discount_cents": 0,
    "discount_percent": 0,
    "tax_cents": 96875,
    "tax_percent": 25,
    "total_cents": 484375,
    "vat_breakdown": [
      {
        "rate": 25,
        "base_cents": 387500,
        "vat_cents": 96875
      }
    ],
    "rot_rut": {
      "type": "rut",
      "rate_percent": 50,
      "labour_cents": 484375,
      "deduction_cents": 242188,
      "customer_pays_cents": 242187,
      "preliminary": true,
      "annual_ceiling_applied": false
    },
    "currency": "SEK",
    "expires_at": "2026-11-17",
    "accepted_at": "2026-10-15T19:44:02+00:00",
    "accepted_by_stakeholder_id": "01a15c47-2b3c-7d4e-8f5a-6b7c8d9e0f1a",
    "acceptance": {
      "via": "room",
      "name": "Anna Ny",
      "email": "anna.ny@example.se",
      "selected_optional_line_ids": [
        "01a15c53-2b3c-7d4e-8f5a-6b7c8d9e0f1b"
      ],
      "total_cents": 484375,
      "tax_cents": 96875,
      "customer_pays_cents": 242187
    },
    "rejection_reason": null,
    "share_url": "https://app.closepact.com/q/k3Jq8vR2mXw9TzL5pN7cH4bY6sD1fG0aE8uQ3iO5rV2tW9xZ",
    "handover": {
      "available": true,
      "target": "work_order",
      "mode": "automatic",
      "work_order": {
        "id": "01a1c0b2-7d4e-7a19-8c35-2f9e6b1d4a07",
        "order_number": "AO-10483",
        "status": "booked"
      },
      "invoice": null,
      "blocked_reason": null
    },
    "lines": [
      {
        "id": "01a15c52-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
        "product_id": "01a15b70-6c7d-7e8f-9a0b-1c2d3e4f5a6b",
        "name": "Hemstäd varannan vecka",
        "description": "Två timmar per tillfälle, RUT-avdrag tillämpas på fakturan.",
        "quantity": 2,
        "unit_price_cents": 160000,
        "discount_percent": 0,
        "vat_rate": 25,
        "line_total_cents": 320000,
        "net_cents": 320000,
        "vat_cents": 80000,
        "line_type": "labour",
        "is_optional": false,
        "is_selected": true,
        "billing_cycle": "monthly",
        "position": 0
      },
      {
        "id": "01a15c53-2b3c-7d4e-8f5a-6b7c8d9e0f1b",
        "product_id": null,
        "name": "Fönsterputs",
        "description": "Tillval: alla fönster, in- och utsida.",
        "quantity": 1.5,
        "unit_price_cents": 45000,
        "discount_percent": 0,
        "vat_rate": 25,
        "line_total_cents": 67500,
        "net_cents": 67500,
        "vat_cents": 16875,
        "line_type": "labour",
        "is_optional": true,
        "is_selected": true,
        "billing_cycle": null,
        "position": 1
      }
    ],
    "created_at": "2026-10-13T08:30:00+00:00",
    "updated_at": "2026-10-15T19:44:02+00:00"
  }
}

Path parameters

  • quotestring(uuid)required

    The quote's id.

Responses

  • Headers

    • X-RateLimit-Limit — Requests this key may make per minute.
    • X-RateLimit-Remaining — Requests left in the current minute.
    • dataobjectrequired
      • idstring(uuid)required
      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired

        The room whose stakeholders can accept the quote.

      • quote_numberstringrequired

        Sequential within the organization.

        Example "Q-00042"

      • titlestringrequired
      • statusstringrequired

        draft until sent, and the only state whose lines and terms can change; sent once in front of the buyer, who can accept or reject it until the end of its expires_at day; accepted or rejected by the buyer, after which it never changes; expired when a sent quote's last day passed unanswered (set by an hourly sweep). A sent or expired quote goes back to draft only through Revert to draft.

        One ofdraftsentacceptedrejectedexpired

      • subtotal_centsintegerrequired

        Sum of the totals of the lines that count, in öre, before the quote discount and VAT.

      • discount_centsintegerrequired

        What the quote's discount_percent took off those lines, in öre.

      • discount_percentintegerrequired

        0–100

      • tax_centsintegerrequired

        The VAT of the lines that count, summed — each line's rounded once. Per rate in vat_breakdown.

      • tax_percentintegerrequireddeprecated

        Deprecated: VAT is per line (lines[].vat_rate, vat_breakdown). Kept for older integrations: it reads as the rate every counted line shares, and is left as it was when the rates are mixed. It never changes an amount.

        0–100

      • total_centsintegerrequired

        What the quote comes to, VAT included, in öre: 400000 is 4 000 kr. Before any ROT/RUT deduction — see rot_rut.customer_pays_cents.

      • vat_breakdownarray of objectsrequired

        Net and VAT per rate over the lines that count, highest rate first — as an invoice has to state them.

      • rot_rutobjectrequired

        A preliminary ROT/RUT estimate, kept apart from the total. The yearly ceiling per person is not applied — it depends on what other companies have already claimed — and Skatteverket decides after the invoice.

      • currencystringrequired

        exactly 3 characters

      • expires_atstring(date)nullablerequired

        Last day the quote can be accepted (inclusive).

      • accepted_atstring(date-time)nullablerequired
      • accepted_by_stakeholder_idstring(uuid)nullablerequired

        The room stakeholder who accepted it, when it was accepted in a room.

      • acceptanceobjectnullablerequired

        What the buyer agreed to, recorded once at the moment of acceptance. Null until accepted, and on quotes accepted before this was recorded.

      • rejection_reasonstringnullablerequired

        What the buyer wrote when rejecting it.

      • share_urlstring(uri)nullablerequired

        The quote's own page, where the buyer can read it, tick options and accept or reject it without a deal room. Issued when the quote is sent, revoked when it is reverted to draft (a new one comes with the next send). Null on a draft. Anyone holding it can answer the quote, so share it only with the buyer.

      • handoverobjectrequired

        What an accepted quote becomes in your organization, and what it became. With the scheduling module it becomes a work order waiting to be planned; with invoicing and no scheduling, an invoice draft. available, target and mode describe your organization and are the same on every quote; work_order, invoice and blocked_reason describe this one. See Hand over an accepted quote.

      • linesarray of objectsrequired
      • created_atstring(date-time)required
      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (module_seat_required — an administrator assigns seats under Settings → Users), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Update a quote

PATCH/quotes/{quote}
Scope write Module Proposals & e-signing Permission cpq.quotes.create

Changes the title, quote-level discount, ROT/RUT estimate or expiry, and recomputes the totals. Fields you leave out are kept. VAT is set on each line, not here.

Only a draft can change. On a sent or expired quote only expires_at may be sent — extending an offer does not change what the buyer would accept — and anything else answers 409 quote_not_draft: revert it to draft first, which withdraws the offer until you send it again. An accepted or rejected quote cannot change at all (409 quote_locked); create a new one instead.

curl -X PATCH 'https://api.closepact.com/v1/api/quotes/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "discount_percent": 10
}'
Response · 200
{
  "data": {
    "id": "01a15c50-8d9e-7f0a-b1c2-d3e4f5a6b7c8",
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": "01a15c40-1f2e-7d9a-8b3c-4e5f6a7b8c9d",
    "quote_number": "Q-00042",
    "title": "Offert hemstädning – familjen Ny",
    "status": "draft",
    "subtotal_cents": 320000,
    "discount_cents": 32000,
    "discount_percent": 10,
    "tax_cents": 72000,
    "tax_percent": 25,
    "total_cents": 360000,
    "vat_breakdown": [
      {
        "rate": 25,
        "base_cents": 288000,
        "vat_cents": 72000
      }
    ],
    "rot_rut": {
      "type": "rut",
      "rate_percent": 50,
      "labour_cents": 360000,
      "deduction_cents": 180000,
      "customer_pays_cents": 180000,
      "preliminary": true,
      "annual_ceiling_applied": false
    },
    "currency": "SEK",
    "expires_at": "2026-11-17",
    "accepted_at": null,
    "accepted_by_stakeholder_id": null,
    "acceptance": null,
    "rejection_reason": null,
    "share_url": null,
    "handover": {
      "available": true,
      "target": "work_order",
      "mode": "automatic",
      "work_order": null,
      "invoice": null,
      "blocked_reason": null
    },
    "lines": [
      {
        "id": "01a15c52-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
        "product_id": "01a15b70-6c7d-7e8f-9a0b-1c2d3e4f5a6b",
        "name": "Hemstäd varannan vecka",
        "description": null,
        "quantity": 2,
        "unit_price_cents": 160000,
        "discount_percent": 0,
        "vat_rate": 25,
        "line_total_cents": 320000,
        "net_cents": 288000,
        "vat_cents": 72000,
        "line_type": "labour",
        "is_optional": false,
        "is_selected": true,
        "billing_cycle": "monthly",
        "position": 0
      }
    ],
    "created_at": "2026-10-13T08:30:00+00:00",
    "updated_at": "2026-10-13T08:52:19+00:00"
  }
}

Path parameters

  • quotestring(uuid)required

    The quote's id.

Request body

application/json · required

  • titlestring

    at most 255 characters

  • discount_percentinteger

    0–100

  • rot_rutstring

    The deduction to estimate: rot (30 %), rut (50 %) or none.

    One ofnonerotrut

  • tax_percentintegerdeprecated

    Deprecated: VAT is set per line. Accepted for older integrations, but it changes no amount.

    0–100

  • expires_atstring(date)nullable

    Last day the quote can be accepted, or null for no limit. Moving it does not change the status of a quote that has already expired.

Responses

  • Headers

    • X-RateLimit-Limit — Requests this key may make per minute.
    • X-RateLimit-Remaining — Requests left in the current minute.
    • dataobjectrequired
      • idstring(uuid)required
      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired

        The room whose stakeholders can accept the quote.

      • quote_numberstringrequired

        Sequential within the organization.

        Example "Q-00042"

      • titlestringrequired
      • statusstringrequired

        draft until sent, and the only state whose lines and terms can change; sent once in front of the buyer, who can accept or reject it until the end of its expires_at day; accepted or rejected by the buyer, after which it never changes; expired when a sent quote's last day passed unanswered (set by an hourly sweep). A sent or expired quote goes back to draft only through Revert to draft.

        One ofdraftsentacceptedrejectedexpired

      • subtotal_centsintegerrequired

        Sum of the totals of the lines that count, in öre, before the quote discount and VAT.

      • discount_centsintegerrequired

        What the quote's discount_percent took off those lines, in öre.

      • discount_percentintegerrequired

        0–100

      • tax_centsintegerrequired

        The VAT of the lines that count, summed — each line's rounded once. Per rate in vat_breakdown.

      • tax_percentintegerrequireddeprecated

        Deprecated: VAT is per line (lines[].vat_rate, vat_breakdown). Kept for older integrations: it reads as the rate every counted line shares, and is left as it was when the rates are mixed. It never changes an amount.

        0–100

      • total_centsintegerrequired

        What the quote comes to, VAT included, in öre: 400000 is 4 000 kr. Before any ROT/RUT deduction — see rot_rut.customer_pays_cents.

      • vat_breakdownarray of objectsrequired

        Net and VAT per rate over the lines that count, highest rate first — as an invoice has to state them.

      • rot_rutobjectrequired

        A preliminary ROT/RUT estimate, kept apart from the total. The yearly ceiling per person is not applied — it depends on what other companies have already claimed — and Skatteverket decides after the invoice.

      • currencystringrequired

        exactly 3 characters

      • expires_atstring(date)nullablerequired

        Last day the quote can be accepted (inclusive).

      • accepted_atstring(date-time)nullablerequired
      • accepted_by_stakeholder_idstring(uuid)nullablerequired

        The room stakeholder who accepted it, when it was accepted in a room.

      • acceptanceobjectnullablerequired

        What the buyer agreed to, recorded once at the moment of acceptance. Null until accepted, and on quotes accepted before this was recorded.

      • rejection_reasonstringnullablerequired

        What the buyer wrote when rejecting it.

      • share_urlstring(uri)nullablerequired

        The quote's own page, where the buyer can read it, tick options and accept or reject it without a deal room. Issued when the quote is sent, revoked when it is reverted to draft (a new one comes with the next send). Null on a draft. Anyone holding it can answer the quote, so share it only with the buyer.

      • handoverobjectrequired

        What an accepted quote becomes in your organization, and what it became. With the scheduling module it becomes a work order waiting to be planned; with invoicing and no scheduling, an invoice draft. available, target and mode describe your organization and are the same on every quote; work_order, invoice and blocked_reason describe this one. See Hand over an accepted quote.

      • linesarray of objectsrequired
      • created_atstring(date-time)required
      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (module_seat_required — an administrator assigns seats under Settings → Users), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 409The quote's state does not allow this. error says which: quote_not_draft — it has been sent; revert it to draft before changing it; quote_locked — it has been accepted or rejected and can no longer change; quote_expired — its last valid day has passed; quote_not_sent, quote_already_accepted, quote_rejected — it is not open for the buyer's answer; quote_not_accepted — only an accepted quote can be handed over; handover_unavailable — the organization has neither the scheduling nor the invoicing module, so an accepted quote has nothing to become. message says the same for a person.
    Errors
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Delete a quote

DELETE/quotes/{quote}
Scope write Module Proposals & e-signing Permission cpq.quotes.create

Deletes the quote: it leaves lists and lookups at once and a later request for it is a 404. Its number is not reused. No webhook fires.

An accepted quote cannot be deleted (409 quote_locked): it is the record of what the buyer agreed to.

curl -X DELETE 'https://api.closepact.com/v1/api/quotes/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 204
204 — no response body

Path parameters

  • quotestring(uuid)required

    The quote's id.

Responses

  • 204The quote was deleted. No body.
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (module_seat_required — an administrator assigns seats under Settings → Users), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 409The quote's state does not allow this. error says which: quote_not_draft — it has been sent; revert it to draft before changing it; quote_locked — it has been accepted or rejected and can no longer change; quote_expired — its last valid day has passed; quote_not_sent, quote_already_accepted, quote_rejected — it is not open for the buyer's answer; quote_not_accepted — only an accepted quote can be handed over; handover_unavailable — the organization has neither the scheduling nor the invoicing module, so an accepted quote has nothing to become. message says the same for a person.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Send a quote

POST/quotes/{quote}/send
Scope write Module Proposals & e-signing Permission cpq.quotes.create

Marks a draft quote sent and gives it its own link, share_url: the buyer opens the quote there, ticks the options they want and accepts or rejects it — no deal room needed. A sent quote in a room also appears on the room's buyer page. Only a sent quote can be accepted or rejected, and only until the end of its expires_at day; acceptance fires the quote.accepted webhook.

With email, the link is e-mailed to that address (with name and message in the letter). Without it nothing is mailed — copy share_url into your own message, or rely on the room. Calling this again on a sent quote keeps its link and can mail it to someone else.

A draft whose expires_at has already passed answers 409 quote_expired: move the date first. Asking to e-mail a quote that can no longer be answered (accepted, rejected or past its expiry) answers 409 too. Otherwise idempotent: a quote that is not a draft is returned unchanged. The body is optional.

curl -X POST 'https://api.closepact.com/v1/api/quotes/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40/send' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "anna.ny@example.se",
  "name": "Anna Ny",
  "message": "Hej Anna! Här är offerten vi pratade om."
}'
Response · 200
{
  "data": {
    "id": "01a15c50-8d9e-7f0a-b1c2-d3e4f5a6b7c8",
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": "01a15c40-1f2e-7d9a-8b3c-4e5f6a7b8c9d",
    "quote_number": "Q-00042",
    "title": "Offert hemstädning – familjen Ny",
    "status": "sent",
    "subtotal_cents": 320000,
    "discount_cents": 0,
    "discount_percent": 0,
    "tax_cents": 80000,
    "tax_percent": 25,
    "total_cents": 400000,
    "vat_breakdown": [
      {
        "rate": 25,
        "base_cents": 320000,
        "vat_cents": 80000
      }
    ],
    "rot_rut": {
      "type": "rut",
      "rate_percent": 50,
      "labour_cents": 400000,
      "deduction_cents": 200000,
      "customer_pays_cents": 200000,
      "preliminary": true,
      "annual_ceiling_applied": false
    },
    "currency": "SEK",
    "expires_at": "2026-11-17",
    "accepted_at": null,
    "accepted_by_stakeholder_id": null,
    "acceptance": null,
    "rejection_reason": null,
    "share_url": "https://app.closepact.com/q/k3Jq8vR2mXw9TzL5pN7cH4bY6sD1fG0aE8uQ3iO5rV2tW9xZ",
    "handover": {
      "available": true,
      "target": "work_order",
      "mode": "automatic",
      "work_order": null,
      "invoice": null,
      "blocked_reason": null
    },
    "lines": [
      {
        "id": "01a15c52-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
        "product_id": "01a15b70-6c7d-7e8f-9a0b-1c2d3e4f5a6b",
        "name": "Hemstäd varannan vecka",
        "description": null,
        "quantity": 2,
        "unit_price_cents": 160000,
        "discount_percent": 0,
        "vat_rate": 25,
        "line_total_cents": 320000,
        "net_cents": 320000,
        "vat_cents": 80000,
        "line_type": "labour",
        "is_optional": false,
        "is_selected": true,
        "billing_cycle": "monthly",
        "position": 0
      }
    ],
    "created_at": "2026-10-13T08:30:00+00:00",
    "updated_at": "2026-10-13T09:05:12+00:00"
  }
}

Path parameters

  • quotestring(uuid)required

    The quote's id.

Request body

application/json

  • emailstring(email)nullable

    Mail the quote's link to this address.

    at most 255 characters

  • namestringnullable

    The recipient's name, for the greeting.

    at most 120 characters

  • messagestringnullable

    A note quoted in the letter.

    at most 2,000 characters

Responses

  • Headers

    • X-RateLimit-Limit — Requests this key may make per minute.
    • X-RateLimit-Remaining — Requests left in the current minute.
    • dataobjectrequired
      • idstring(uuid)required
      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired

        The room whose stakeholders can accept the quote.

      • quote_numberstringrequired

        Sequential within the organization.

        Example "Q-00042"

      • titlestringrequired
      • statusstringrequired

        draft until sent, and the only state whose lines and terms can change; sent once in front of the buyer, who can accept or reject it until the end of its expires_at day; accepted or rejected by the buyer, after which it never changes; expired when a sent quote's last day passed unanswered (set by an hourly sweep). A sent or expired quote goes back to draft only through Revert to draft.

        One ofdraftsentacceptedrejectedexpired

      • subtotal_centsintegerrequired

        Sum of the totals of the lines that count, in öre, before the quote discount and VAT.

      • discount_centsintegerrequired

        What the quote's discount_percent took off those lines, in öre.

      • discount_percentintegerrequired

        0–100

      • tax_centsintegerrequired

        The VAT of the lines that count, summed — each line's rounded once. Per rate in vat_breakdown.

      • tax_percentintegerrequireddeprecated

        Deprecated: VAT is per line (lines[].vat_rate, vat_breakdown). Kept for older integrations: it reads as the rate every counted line shares, and is left as it was when the rates are mixed. It never changes an amount.

        0–100

      • total_centsintegerrequired

        What the quote comes to, VAT included, in öre: 400000 is 4 000 kr. Before any ROT/RUT deduction — see rot_rut.customer_pays_cents.

      • vat_breakdownarray of objectsrequired

        Net and VAT per rate over the lines that count, highest rate first — as an invoice has to state them.

      • rot_rutobjectrequired

        A preliminary ROT/RUT estimate, kept apart from the total. The yearly ceiling per person is not applied — it depends on what other companies have already claimed — and Skatteverket decides after the invoice.

      • currencystringrequired

        exactly 3 characters

      • expires_atstring(date)nullablerequired

        Last day the quote can be accepted (inclusive).

      • accepted_atstring(date-time)nullablerequired
      • accepted_by_stakeholder_idstring(uuid)nullablerequired

        The room stakeholder who accepted it, when it was accepted in a room.

      • acceptanceobjectnullablerequired

        What the buyer agreed to, recorded once at the moment of acceptance. Null until accepted, and on quotes accepted before this was recorded.

      • rejection_reasonstringnullablerequired

        What the buyer wrote when rejecting it.

      • share_urlstring(uri)nullablerequired

        The quote's own page, where the buyer can read it, tick options and accept or reject it without a deal room. Issued when the quote is sent, revoked when it is reverted to draft (a new one comes with the next send). Null on a draft. Anyone holding it can answer the quote, so share it only with the buyer.

      • handoverobjectrequired

        What an accepted quote becomes in your organization, and what it became. With the scheduling module it becomes a work order waiting to be planned; with invoicing and no scheduling, an invoice draft. available, target and mode describe your organization and are the same on every quote; work_order, invoice and blocked_reason describe this one. See Hand over an accepted quote.

      • linesarray of objectsrequired
      • created_atstring(date-time)required
      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (module_seat_required — an administrator assigns seats under Settings → Users), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 409The quote's state does not allow this. error says which: quote_not_draft — it has been sent; revert it to draft before changing it; quote_locked — it has been accepted or rejected and can no longer change; quote_expired — its last valid day has passed; quote_not_sent, quote_already_accepted, quote_rejected — it is not open for the buyer's answer; quote_not_accepted — only an accepted quote can be handed over; handover_unavailable — the organization has neither the scheduling nor the invoicing module, so an accepted quote has nothing to become. message says the same for a person.
    Errors
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Revert a quote to draft

POST/quotes/{quote}/revert-to-draft
Scope write Module Proposals & e-signing Permission cpq.quotes.create

Takes a sent or expired quote back to draft so its lines and terms can be changed. This withdraws the offer: a draft cannot be accepted, so it leaves the room's buyer page and its share_url stops working, until you send the revised quote again — with a new link, so nobody can accept the revision from a link to the old offer.

An accepted or rejected quote cannot be reverted (409 quote_locked). Idempotent on a draft. No request body.

curl -X POST 'https://api.closepact.com/v1/api/quotes/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40/revert-to-draft' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 200
{
  "data": {
    "id": "01a15c50-8d9e-7f0a-b1c2-d3e4f5a6b7c8",
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": "01a15c40-1f2e-7d9a-8b3c-4e5f6a7b8c9d",
    "quote_number": "Q-00042",
    "title": "Offert hemstädning – familjen Ny",
    "status": "draft",
    "subtotal_cents": 320000,
    "discount_cents": 0,
    "discount_percent": 0,
    "tax_cents": 80000,
    "tax_percent": 25,
    "total_cents": 400000,
    "vat_breakdown": [
      {
        "rate": 25,
        "base_cents": 320000,
        "vat_cents": 80000
      }
    ],
    "rot_rut": {
      "type": "rut",
      "rate_percent": 50,
      "labour_cents": 400000,
      "deduction_cents": 200000,
      "customer_pays_cents": 200000,
      "preliminary": true,
      "annual_ceiling_applied": false
    },
    "currency": "SEK",
    "expires_at": "2026-11-17",
    "accepted_at": null,
    "accepted_by_stakeholder_id": null,
    "acceptance": null,
    "rejection_reason": null,
    "share_url": null,
    "handover": {
      "available": true,
      "target": "work_order",
      "mode": "automatic",
      "work_order": null,
      "invoice": null,
      "blocked_reason": null
    },
    "lines": [
      {
        "id": "01a15c52-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
        "product_id": "01a15b70-6c7d-7e8f-9a0b-1c2d3e4f5a6b",
        "name": "Hemstäd varannan vecka",
        "description": null,
        "quantity": 2,
        "unit_price_cents": 160000,
        "discount_percent": 0,
        "vat_rate": 25,
        "line_total_cents": 320000,
        "net_cents": 320000,
        "vat_cents": 80000,
        "line_type": "labour",
        "is_optional": false,
        "is_selected": true,
        "billing_cycle": "monthly",
        "position": 0
      }
    ],
    "created_at": "2026-10-13T08:30:00+00:00",
    "updated_at": "2026-10-14T10:12:40+00:00"
  }
}

Path parameters

  • quotestring(uuid)required

    The quote's id.

Responses

  • Headers

    • X-RateLimit-Limit — Requests this key may make per minute.
    • X-RateLimit-Remaining — Requests left in the current minute.
    • dataobjectrequired
      • idstring(uuid)required
      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired

        The room whose stakeholders can accept the quote.

      • quote_numberstringrequired

        Sequential within the organization.

        Example "Q-00042"

      • titlestringrequired
      • statusstringrequired

        draft until sent, and the only state whose lines and terms can change; sent once in front of the buyer, who can accept or reject it until the end of its expires_at day; accepted or rejected by the buyer, after which it never changes; expired when a sent quote's last day passed unanswered (set by an hourly sweep). A sent or expired quote goes back to draft only through Revert to draft.

        One ofdraftsentacceptedrejectedexpired

      • subtotal_centsintegerrequired

        Sum of the totals of the lines that count, in öre, before the quote discount and VAT.

      • discount_centsintegerrequired

        What the quote's discount_percent took off those lines, in öre.

      • discount_percentintegerrequired

        0–100

      • tax_centsintegerrequired

        The VAT of the lines that count, summed — each line's rounded once. Per rate in vat_breakdown.

      • tax_percentintegerrequireddeprecated

        Deprecated: VAT is per line (lines[].vat_rate, vat_breakdown). Kept for older integrations: it reads as the rate every counted line shares, and is left as it was when the rates are mixed. It never changes an amount.

        0–100

      • total_centsintegerrequired

        What the quote comes to, VAT included, in öre: 400000 is 4 000 kr. Before any ROT/RUT deduction — see rot_rut.customer_pays_cents.

      • vat_breakdownarray of objectsrequired

        Net and VAT per rate over the lines that count, highest rate first — as an invoice has to state them.

      • rot_rutobjectrequired

        A preliminary ROT/RUT estimate, kept apart from the total. The yearly ceiling per person is not applied — it depends on what other companies have already claimed — and Skatteverket decides after the invoice.

      • currencystringrequired

        exactly 3 characters

      • expires_atstring(date)nullablerequired

        Last day the quote can be accepted (inclusive).

      • accepted_atstring(date-time)nullablerequired
      • accepted_by_stakeholder_idstring(uuid)nullablerequired

        The room stakeholder who accepted it, when it was accepted in a room.

      • acceptanceobjectnullablerequired

        What the buyer agreed to, recorded once at the moment of acceptance. Null until accepted, and on quotes accepted before this was recorded.

      • rejection_reasonstringnullablerequired

        What the buyer wrote when rejecting it.

      • share_urlstring(uri)nullablerequired

        The quote's own page, where the buyer can read it, tick options and accept or reject it without a deal room. Issued when the quote is sent, revoked when it is reverted to draft (a new one comes with the next send). Null on a draft. Anyone holding it can answer the quote, so share it only with the buyer.

      • handoverobjectrequired

        What an accepted quote becomes in your organization, and what it became. With the scheduling module it becomes a work order waiting to be planned; with invoicing and no scheduling, an invoice draft. available, target and mode describe your organization and are the same on every quote; work_order, invoice and blocked_reason describe this one. See Hand over an accepted quote.

      • linesarray of objectsrequired
      • created_atstring(date-time)required
      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (module_seat_required — an administrator assigns seats under Settings → Users), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 409The quote's state does not allow this. error says which: quote_not_draft — it has been sent; revert it to draft before changing it; quote_locked — it has been accepted or rejected and can no longer change; quote_expired — its last valid day has passed; quote_not_sent, quote_already_accepted, quote_rejected — it is not open for the buyer's answer; quote_not_accepted — only an accepted quote can be handed over; handover_unavailable — the organization has neither the scheduling nor the invoicing module, so an accepted quote has nothing to become. message says the same for a person.
    Errors
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Hand over an accepted quote

POST/quotes/{quote}/convert
Scope write Module Proposals & e-signing Any permission of booking.work_orders.manage,invoicing.invoices.manage

Turns an accepted quote into what your organization does with one: a work order waiting to be planned when you have the scheduling module, otherwise an invoice draft when you have the invoicing module — the panel's Create job or Create invoice draft button. Usually it happens by itself the moment the buyer accepts; call this when your organization hands quotes over manually (handover.mode is manual), or when acceptance could not do it (handover.blocked_reason).

What the buyer agreed to is carried over as agreed: the customer, the contact who accepted, the title, the lines they accepted (optional lines only if they ticked them) at the quoted quantities, prices, discounts and VAT rates, and the ROT/RUT choice. A line made from a product linked to a service (service_id on the product) becomes that service on the work order; other work becomes a service line of free text and materials become material lines. The work order is booked with no time on it, at the customer's default service address. An invoice draft has no number and is never sent by this call. What could not be filled in is listed in the work order's or draft's handover.warnings.

A quote is handed over once. If it already was — by acceptance, or an earlier call — the answer is 200 with the same quote and nothing new is made; a work order deleted afterwards can be made again with this call. handover in the response says what the quote became.

Needs the quote-to-job capability (proposals.convert, proposals Väx and Pro), and the member the key acts as must be allowed to create work orders (booking.work_orders.manage) or, where quotes become invoices, invoice drafts (invoicing.invoices.manage). Refused with 409 quote_not_accepted for a quote that is not accepted and handover_unavailable without either module; with 422 on account_id when the quote is tied to no customer and none was given.

curl -X POST 'https://api.closepact.com/v1/api/quotes/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40/convert' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "account_id": "01a15a77-0d3b-7e21-a6f9-3c8e2b1d4a05"
}'
Response
{
  "data": {
    "id": "01a1bf90-2c6a-7e45-9d18-4b7f3a0e6c21",
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": null,
    "quote_number": "Q-2026-0142",
    "title": "Fönsterbyte Solna – offert",
    "status": "accepted",
    "subtotal_cents": 1200000,
    "discount_cents": 0,
    "discount_percent": 0,
    "tax_cents": 300000,
    "tax_percent": 25,
    "total_cents": 1500000,
    "vat_breakdown": [
      {
        "rate": 25,
        "base_cents": 1200000,
        "vat_cents": 300000
      }
    ],
    "rot_rut": {
      "type": "none",
      "rate_percent": null,
      "labour_cents": 0,
      "deduction_cents": 0,
      "customer_pays_cents": 1500000,
      "preliminary": true,
      "annual_ceiling_applied": false
    },
    "currency": "SEK",
    "expires_at": "2026-11-15",
    "accepted_at": "2026-10-18T08:41:12+00:00",
    "accepted_by_stakeholder_id": null,
    "acceptance": {
      "via": "link",
      "name": "Eva Ek",
      "email": "eva.ek@example.se",
      "selected_optional_line_ids": [],
      "total_cents": 1500000,
      "tax_cents": 300000,
      "customer_pays_cents": 1500000
    },
    "rejection_reason": null,
    "share_url": "https://app.closepact.com/q/k3Jq8vR2mXw9TzL5pN7cH4bY6sD1fG0aE8uQ3iO5rV2tW9xZ",
    "handover": {
      "available": true,
      "target": "invoice",
      "mode": "automatic",
      "work_order": null,
      "invoice": {
        "id": "01a1c1e8-5a3d-7b62-9f40-8c2e1d7b0a95",
        "status": "draft",
        "reference": "Utkast"
      },
      "blocked_reason": null
    },
    "lines": [],
    "created_at": "2026-10-13T08:30:00+00:00",
    "updated_at": "2026-10-18T08:41:12+00:00"
  }
}

Path parameters

  • quotestring(uuid)required

    The quote's id.

Request body

application/json

  • account_idstring(uuid)nullable

    The customer the work order or draft is for. Defaults to the quote's: the customer of its deal (or its room's deal), else the customer of the contact who accepted. Required when the quote has none.

  • service_address_idstring(uuid)nullable

    One of the customer's addresses, where the work happens. Defaults to the customer's default service address, or its only one.

Responses

  • Headers

    • X-RateLimit-Limit — Requests this key may make per minute.
    • X-RateLimit-Remaining — Requests left in the current minute.
    • dataobjectrequired
      • idstring(uuid)required
      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired

        The room whose stakeholders can accept the quote.

      • quote_numberstringrequired

        Sequential within the organization.

        Example "Q-00042"

      • titlestringrequired
      • statusstringrequired

        draft until sent, and the only state whose lines and terms can change; sent once in front of the buyer, who can accept or reject it until the end of its expires_at day; accepted or rejected by the buyer, after which it never changes; expired when a sent quote's last day passed unanswered (set by an hourly sweep). A sent or expired quote goes back to draft only through Revert to draft.

        One ofdraftsentacceptedrejectedexpired

      • subtotal_centsintegerrequired

        Sum of the totals of the lines that count, in öre, before the quote discount and VAT.

      • discount_centsintegerrequired

        What the quote's discount_percent took off those lines, in öre.

      • discount_percentintegerrequired

        0–100

      • tax_centsintegerrequired

        The VAT of the lines that count, summed — each line's rounded once. Per rate in vat_breakdown.

      • tax_percentintegerrequireddeprecated

        Deprecated: VAT is per line (lines[].vat_rate, vat_breakdown). Kept for older integrations: it reads as the rate every counted line shares, and is left as it was when the rates are mixed. It never changes an amount.

        0–100

      • total_centsintegerrequired

        What the quote comes to, VAT included, in öre: 400000 is 4 000 kr. Before any ROT/RUT deduction — see rot_rut.customer_pays_cents.

      • vat_breakdownarray of objectsrequired

        Net and VAT per rate over the lines that count, highest rate first — as an invoice has to state them.

      • rot_rutobjectrequired

        A preliminary ROT/RUT estimate, kept apart from the total. The yearly ceiling per person is not applied — it depends on what other companies have already claimed — and Skatteverket decides after the invoice.

      • currencystringrequired

        exactly 3 characters

      • expires_atstring(date)nullablerequired

        Last day the quote can be accepted (inclusive).

      • accepted_atstring(date-time)nullablerequired
      • accepted_by_stakeholder_idstring(uuid)nullablerequired

        The room stakeholder who accepted it, when it was accepted in a room.

      • acceptanceobjectnullablerequired

        What the buyer agreed to, recorded once at the moment of acceptance. Null until accepted, and on quotes accepted before this was recorded.

      • rejection_reasonstringnullablerequired

        What the buyer wrote when rejecting it.

      • share_urlstring(uri)nullablerequired

        The quote's own page, where the buyer can read it, tick options and accept or reject it without a deal room. Issued when the quote is sent, revoked when it is reverted to draft (a new one comes with the next send). Null on a draft. Anyone holding it can answer the quote, so share it only with the buyer.

      • handoverobjectrequired

        What an accepted quote becomes in your organization, and what it became. With the scheduling module it becomes a work order waiting to be planned; with invoicing and no scheduling, an invoice draft. available, target and mode describe your organization and are the same on every quote; work_order, invoice and blocked_reason describe this one. See Hand over an accepted quote.

      • linesarray of objectsrequired
      • created_atstring(date-time)required
      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (module_seat_required — an administrator assigns seats under Settings → Users), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 409The quote's state does not allow this. error says which: quote_not_draft — it has been sent; revert it to draft before changing it; quote_locked — it has been accepted or rejected and can no longer change; quote_expired — its last valid day has passed; quote_not_sent, quote_already_accepted, quote_rejected — it is not open for the buyer's answer; quote_not_accepted — only an accepted quote can be handed over; handover_unavailable — the organization has neither the scheduling nor the invoicing module, so an accepted quote has nothing to become. message says the same for a person.
    Errors
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Add a line

POST/quotes/{quote}/lines
Scope write Module Proposals & e-signing Permission cpq.quotes.create

Appends a line to the quote and recomputes its totals. Answers with the whole quote.

With product_id, the line starts from that catalogue product: its name, description, unit price, VAT rate and billing cycle are copied onto the line (a snapshot — later changes to the product do not reach the quote), and anything you send overrides them. Without it, name is required, the price defaults to 0 and the VAT rate to 25.

An optional line (is_optional: true) is priced like any other but counts in the totals only while is_selected; it starts unticked unless you send is_selected: true to suggest it. The buyer makes the final choice when accepting.

Only a draft's lines change: on a sent or expired quote this answers 409 quote_not_draft (revert it to draft first), on an accepted or rejected one 409 quote_locked.

Not idempotent: each call adds another line.

curl -X POST 'https://api.closepact.com/v1/api/quotes/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40/lines' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "product_id": "01a15b70-6c7d-7e8f-9a0b-1c2d3e4f5a6b",
  "quantity": 2,
  "line_type": "labour"
}'
Response · 201
{
  "data": {
    "id": "01a15c50-8d9e-7f0a-b1c2-d3e4f5a6b7c8",
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": "01a15c40-1f2e-7d9a-8b3c-4e5f6a7b8c9d",
    "quote_number": "Q-00042",
    "title": "Offert hemstädning – familjen Ny",
    "status": "draft",
    "subtotal_cents": 320000,
    "discount_cents": 0,
    "discount_percent": 0,
    "tax_cents": 80000,
    "tax_percent": 25,
    "total_cents": 400000,
    "vat_breakdown": [
      {
        "rate": 25,
        "base_cents": 320000,
        "vat_cents": 80000
      }
    ],
    "rot_rut": {
      "type": "rut",
      "rate_percent": 50,
      "labour_cents": 400000,
      "deduction_cents": 200000,
      "customer_pays_cents": 200000,
      "preliminary": true,
      "annual_ceiling_applied": false
    },
    "currency": "SEK",
    "expires_at": "2026-11-17",
    "accepted_at": null,
    "accepted_by_stakeholder_id": null,
    "acceptance": null,
    "rejection_reason": null,
    "share_url": null,
    "handover": {
      "available": true,
      "target": "work_order",
      "mode": "automatic",
      "work_order": null,
      "invoice": null,
      "blocked_reason": null
    },
    "lines": [
      {
        "id": "01a15c52-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
        "product_id": "01a15b70-6c7d-7e8f-9a0b-1c2d3e4f5a6b",
        "name": "Hemstäd varannan vecka",
        "description": null,
        "quantity": 2,
        "unit_price_cents": 160000,
        "discount_percent": 0,
        "vat_rate": 25,
        "line_total_cents": 320000,
        "net_cents": 320000,
        "vat_cents": 80000,
        "line_type": "labour",
        "is_optional": false,
        "is_selected": true,
        "billing_cycle": "monthly",
        "position": 0
      }
    ],
    "created_at": "2026-10-13T08:30:00+00:00",
    "updated_at": "2026-10-13T08:41:57+00:00"
  }
}

Path parameters

  • quotestring(uuid)required

    The quote's id.

Request body

application/json · required

  • product_idstring(uuid)nullable

    A product in this organization's catalogue.

  • namestringnullable

    Required without product_id.

    at most 255 characters

  • descriptionstringnullable

    at most 2,000 characters

  • quantitynumberrequired

    Up to three decimals: 2.5 hours, 13.75 m².

    0.001–100,000

  • unit_price_centsintegernullable

    Price per unit in öre, excluding VAT. Defaults to the product's price, or 0.

    ≥ 0

  • discount_percentintegernullable

    Default 00–100

  • vat_ratenumbernullable

    Moms in percent. Defaults to the product's rate, or 25.

    One of251260

  • line_typestringnullable

    Only labour counts towards a ROT/RUT deduction.

    One oflabourmaterialother

    Default "other"

  • is_optionalbooleannullable

    An option the buyer may tick in or out.

    Default false

  • is_selectedbooleannullable

    For an optional line: counted in the totals until the buyer decides. Ignored for a fixed line, which always counts.

    Default false

  • billing_cyclestringnullable

    For recurring lines. Defaults to the product's.

    One ofmonthlyyearly

Responses

  • Headers

    • X-RateLimit-Limit — Requests this key may make per minute.
    • X-RateLimit-Remaining — Requests left in the current minute.
    • dataobjectrequired
      • idstring(uuid)required
      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired

        The room whose stakeholders can accept the quote.

      • quote_numberstringrequired

        Sequential within the organization.

        Example "Q-00042"

      • titlestringrequired
      • statusstringrequired

        draft until sent, and the only state whose lines and terms can change; sent once in front of the buyer, who can accept or reject it until the end of its expires_at day; accepted or rejected by the buyer, after which it never changes; expired when a sent quote's last day passed unanswered (set by an hourly sweep). A sent or expired quote goes back to draft only through Revert to draft.

        One ofdraftsentacceptedrejectedexpired

      • subtotal_centsintegerrequired

        Sum of the totals of the lines that count, in öre, before the quote discount and VAT.

      • discount_centsintegerrequired

        What the quote's discount_percent took off those lines, in öre.

      • discount_percentintegerrequired

        0–100

      • tax_centsintegerrequired

        The VAT of the lines that count, summed — each line's rounded once. Per rate in vat_breakdown.

      • tax_percentintegerrequireddeprecated

        Deprecated: VAT is per line (lines[].vat_rate, vat_breakdown). Kept for older integrations: it reads as the rate every counted line shares, and is left as it was when the rates are mixed. It never changes an amount.

        0–100

      • total_centsintegerrequired

        What the quote comes to, VAT included, in öre: 400000 is 4 000 kr. Before any ROT/RUT deduction — see rot_rut.customer_pays_cents.

      • vat_breakdownarray of objectsrequired

        Net and VAT per rate over the lines that count, highest rate first — as an invoice has to state them.

      • rot_rutobjectrequired

        A preliminary ROT/RUT estimate, kept apart from the total. The yearly ceiling per person is not applied — it depends on what other companies have already claimed — and Skatteverket decides after the invoice.

      • currencystringrequired

        exactly 3 characters

      • expires_atstring(date)nullablerequired

        Last day the quote can be accepted (inclusive).

      • accepted_atstring(date-time)nullablerequired
      • accepted_by_stakeholder_idstring(uuid)nullablerequired

        The room stakeholder who accepted it, when it was accepted in a room.

      • acceptanceobjectnullablerequired

        What the buyer agreed to, recorded once at the moment of acceptance. Null until accepted, and on quotes accepted before this was recorded.

      • rejection_reasonstringnullablerequired

        What the buyer wrote when rejecting it.

      • share_urlstring(uri)nullablerequired

        The quote's own page, where the buyer can read it, tick options and accept or reject it without a deal room. Issued when the quote is sent, revoked when it is reverted to draft (a new one comes with the next send). Null on a draft. Anyone holding it can answer the quote, so share it only with the buyer.

      • handoverobjectrequired

        What an accepted quote becomes in your organization, and what it became. With the scheduling module it becomes a work order waiting to be planned; with invoicing and no scheduling, an invoice draft. available, target and mode describe your organization and are the same on every quote; work_order, invoice and blocked_reason describe this one. See Hand over an accepted quote.

      • linesarray of objectsrequired
      • created_atstring(date-time)required
      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (module_seat_required — an administrator assigns seats under Settings → Users), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 409The quote's state does not allow this. error says which: quote_not_draft — it has been sent; revert it to draft before changing it; quote_locked — it has been accepted or rejected and can no longer change; quote_expired — its last valid day has passed; quote_not_sent, quote_already_accepted, quote_rejected — it is not open for the buyer's answer; quote_not_accepted — only an accepted quote can be handed over; handover_unavailable — the organization has neither the scheduling nor the invoicing module, so an accepted quote has nothing to become. message says the same for a person.
    Errors
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Update a line

PATCH/quotes/{quote}/lines/{line}
Scope write Module Proposals & e-signing Permission cpq.quotes.create

Changes the fields you send and recomputes the quote's totals. Answers with the whole quote. A field sent as null is left as it is, so a line's description or billing cycle cannot be cleared here — replace the line instead. The product a line came from cannot be changed. Only a draft's lines change (409 otherwise, as for adding one).

curl -X PATCH 'https://api.closepact.com/v1/api/quotes/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40/lines/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "quantity": 4,
  "discount_percent": 5
}'
Response · 200
{
  "data": {
    "id": "01a15c50-8d9e-7f0a-b1c2-d3e4f5a6b7c8",
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": "01a15c40-1f2e-7d9a-8b3c-4e5f6a7b8c9d",
    "quote_number": "Q-00042",
    "title": "Offert hemstädning – familjen Ny",
    "status": "draft",
    "subtotal_cents": 608000,
    "discount_cents": 0,
    "discount_percent": 0,
    "tax_cents": 152000,
    "tax_percent": 25,
    "total_cents": 760000,
    "vat_breakdown": [
      {
        "rate": 25,
        "base_cents": 608000,
        "vat_cents": 152000
      }
    ],
    "rot_rut": {
      "type": "rut",
      "rate_percent": 50,
      "labour_cents": 760000,
      "deduction_cents": 380000,
      "customer_pays_cents": 380000,
      "preliminary": true,
      "annual_ceiling_applied": false
    },
    "currency": "SEK",
    "expires_at": "2026-11-17",
    "accepted_at": null,
    "accepted_by_stakeholder_id": null,
    "acceptance": null,
    "rejection_reason": null,
    "share_url": null,
    "handover": {
      "available": true,
      "target": "work_order",
      "mode": "automatic",
      "work_order": null,
      "invoice": null,
      "blocked_reason": null
    },
    "lines": [
      {
        "id": "01a15c52-1a2b-7c3d-8e4f-5a6b7c8d9e0f",
        "product_id": "01a15b70-6c7d-7e8f-9a0b-1c2d3e4f5a6b",
        "name": "Hemstäd varannan vecka",
        "description": null,
        "quantity": 4,
        "unit_price_cents": 160000,
        "discount_percent": 5,
        "vat_rate": 25,
        "line_total_cents": 608000,
        "net_cents": 608000,
        "vat_cents": 152000,
        "line_type": "labour",
        "is_optional": false,
        "is_selected": true,
        "billing_cycle": "monthly",
        "position": 0
      }
    ],
    "created_at": "2026-10-13T08:30:00+00:00",
    "updated_at": "2026-10-13T08:47:03+00:00"
  }
}

Path parameters

  • quotestring(uuid)required

    The quote's id.

  • linestring(uuid)required

    The line's id. It must belong to this quote.

Request body

application/json · required

  • namestringnullable

    at most 255 characters

  • descriptionstringnullable

    at most 2,000 characters

  • quantitynumbernullable

    Up to three decimals.

    0.001–100,000

  • unit_price_centsintegernullable

    ≥ 0

  • discount_percentintegernullable

    0–100

  • vat_ratenumbernullable

    One of251260

  • line_typestringnullable

    One oflabourmaterialother

  • is_optionalbooleannullable

    Making a line fixed counts it again; making it optional leaves it unticked unless is_selected says otherwise.

  • is_selectedbooleannullable

    For an optional line only.

  • billing_cyclestringnullable

    One ofmonthlyyearly

Responses

  • Headers

    • X-RateLimit-Limit — Requests this key may make per minute.
    • X-RateLimit-Remaining — Requests left in the current minute.
    • dataobjectrequired
      • idstring(uuid)required
      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired

        The room whose stakeholders can accept the quote.

      • quote_numberstringrequired

        Sequential within the organization.

        Example "Q-00042"

      • titlestringrequired
      • statusstringrequired

        draft until sent, and the only state whose lines and terms can change; sent once in front of the buyer, who can accept or reject it until the end of its expires_at day; accepted or rejected by the buyer, after which it never changes; expired when a sent quote's last day passed unanswered (set by an hourly sweep). A sent or expired quote goes back to draft only through Revert to draft.

        One ofdraftsentacceptedrejectedexpired

      • subtotal_centsintegerrequired

        Sum of the totals of the lines that count, in öre, before the quote discount and VAT.

      • discount_centsintegerrequired

        What the quote's discount_percent took off those lines, in öre.

      • discount_percentintegerrequired

        0–100

      • tax_centsintegerrequired

        The VAT of the lines that count, summed — each line's rounded once. Per rate in vat_breakdown.

      • tax_percentintegerrequireddeprecated

        Deprecated: VAT is per line (lines[].vat_rate, vat_breakdown). Kept for older integrations: it reads as the rate every counted line shares, and is left as it was when the rates are mixed. It never changes an amount.

        0–100

      • total_centsintegerrequired

        What the quote comes to, VAT included, in öre: 400000 is 4 000 kr. Before any ROT/RUT deduction — see rot_rut.customer_pays_cents.

      • vat_breakdownarray of objectsrequired

        Net and VAT per rate over the lines that count, highest rate first — as an invoice has to state them.

      • rot_rutobjectrequired

        A preliminary ROT/RUT estimate, kept apart from the total. The yearly ceiling per person is not applied — it depends on what other companies have already claimed — and Skatteverket decides after the invoice.

      • currencystringrequired

        exactly 3 characters

      • expires_atstring(date)nullablerequired

        Last day the quote can be accepted (inclusive).

      • accepted_atstring(date-time)nullablerequired
      • accepted_by_stakeholder_idstring(uuid)nullablerequired

        The room stakeholder who accepted it, when it was accepted in a room.

      • acceptanceobjectnullablerequired

        What the buyer agreed to, recorded once at the moment of acceptance. Null until accepted, and on quotes accepted before this was recorded.

      • rejection_reasonstringnullablerequired

        What the buyer wrote when rejecting it.

      • share_urlstring(uri)nullablerequired

        The quote's own page, where the buyer can read it, tick options and accept or reject it without a deal room. Issued when the quote is sent, revoked when it is reverted to draft (a new one comes with the next send). Null on a draft. Anyone holding it can answer the quote, so share it only with the buyer.

      • handoverobjectrequired

        What an accepted quote becomes in your organization, and what it became. With the scheduling module it becomes a work order waiting to be planned; with invoicing and no scheduling, an invoice draft. available, target and mode describe your organization and are the same on every quote; work_order, invoice and blocked_reason describe this one. See Hand over an accepted quote.

      • linesarray of objectsrequired
      • created_atstring(date-time)required
      • updated_atstring(date-time)required
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (module_seat_required — an administrator assigns seats under Settings → Users), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 409The quote's state does not allow this. error says which: quote_not_draft — it has been sent; revert it to draft before changing it; quote_locked — it has been accepted or rejected and can no longer change; quote_expired — its last valid day has passed; quote_not_sent, quote_already_accepted, quote_rejected — it is not open for the buyer's answer; quote_not_accepted — only an accepted quote can be handed over; handover_unavailable — the organization has neither the scheduling nor the invoicing module, so an accepted quote has nothing to become. message says the same for a person.
    Errors
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Delete a line

DELETE/quotes/{quote}/lines/{line}
Scope write Module Proposals & e-signing Permission cpq.quotes.create

Removes the line and recomputes the quote's totals. The other lines keep their positions. Only a draft's lines change (409 otherwise, as for adding one).

curl -X DELETE 'https://api.closepact.com/v1/api/quotes/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40/lines/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 204
204 — no response body

Path parameters

  • quotestring(uuid)required

    The quote's id.

  • linestring(uuid)required

    The line's id. It must belong to this quote.

Responses

  • 204The line was deleted. No body.
  • 401No key, or the key is invalid, revoked or expired, or its creator no longer has access.
    Errors
  • 402The organization has not bought the module this endpoint belongs to, or it has lapsed to read-only, or its tier does not include what the operation needs: feature names the capability (the operation's x-feature) and required_tier the cheapest tier that grants it. Every operation answers this with "feature": "core.api" when no module the organization holds is on a tier that includes the API.
    Errors
  • 403The key lacks the scope, or the member it acts as lacks the permission or holds no seat in the module (module_seat_required — an administrator assigns seats under Settings → Users), or the organization is suspended.
    Errors
  • 404No such record in this organization.
    Errors
  • 409The quote's state does not allow this. error says which: quote_not_draft — it has been sent; revert it to draft before changing it; quote_locked — it has been accepted or rejected and can no longer change; quote_expired — its last valid day has passed; quote_not_sent, quote_already_accepted, quote_rejected — it is not open for the buyer's answer; quote_not_accepted — only an accepted quote can be handed over; handover_unavailable — the organization has neither the scheduling nor the invoicing module, so an accepted quote has nothing to become. message says the same for a person.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors