Proposals

Written proposals, edited in the panel's editor as a tree of blocks (headings, paragraphs, lists, images, pricing tables…). Every edit of the content is kept as a numbered version.

List proposals

GET/proposals

Returns the organization's proposals, most recently changed first, with their full content, 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/proposals' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 200
{
  "data": [
    {
      "id": "01a15c60-4e5f-7a6b-8c7d-9e0f1a2b3c4d",
      "title": "Förslag hemstädning",
      "status": "published",
      "current_version": 3,
      "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
      "deal_room_id": "01a15c40-1f2e-7d9a-8b3c-4e5f6a7b8c9d",
      "blocks": [
        {
          "type": "heading",
          "attrs": {
            "level": 1
          },
          "content": [
            {
              "type": "text",
              "text": "Hemstäd för familjen Ny"
            }
          ]
        },
        {
          "type": "paragraph",
          "content": [
            {
              "type": "text",
              "text": "Varannan vecka, två timmar per tillfälle."
            }
          ]
        }
      ],
      "settings": [],
      "published_at": "2026-10-14T07:30:00+00:00",
      "created_at": "2026-10-12T09:00:00+00:00",
      "updated_at": "2026-10-14T07:30:00+00:00"
    }
  ],
  "links": {
    "first": null,
    "last": null,
    "prev": null,
    "next": null
  },
  "meta": {
    "path": "https://api.closepact.com/v1/api/proposals",
    "per_page": 25,
    "next_cursor": null,
    "prev_cursor": null
  }
}

Query parameters

  • deal_idstring(uuid)

    Only proposals for this deal.

  • deal_room_idstring(uuid)

    Only proposals for this room.

  • 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
      • titlestringrequired
      • statusstringrequired

        draft while being written; in_review when held for approval in the panel; published once released.

        One ofdraftin_reviewpublished

      • current_versionintegerrequired

        Goes up by one with every content change.

        ≥ 1

      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired
      • blocksarray of objectsrequired
      • settingsobject | array of valuesnullablerequired

        Editor display settings. An empty set comes back as [].

        at most 0 items

      • published_atstring(date-time)nullablerequired
      • 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 proposal

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

Creates a draft proposal, optionally with content, and saves it as version 1 ("Initial draft") under the member the key acts as.

Blocks are checked before anything is saved: an unknown block type anywhere in the tree is a 422. Keys a block does not support are dropped, and text longer than 10 000 characters is cut. Not idempotent: each call creates another proposal.

curl -X POST 'https://api.closepact.com/v1/api/proposals' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Förslag hemstädning",
  "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
  "blocks": [
    {
      "type": "heading",
      "attrs": {
        "level": 1
      },
      "content": [
        {
          "type": "text",
          "text": "Hemstäd för familjen Ny"
        }
      ]
    },
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "text": "Varannan vecka, två timmar per tillfälle."
        }
      ]
    }
  ]
}'
Response · 201
{
  "data": {
    "id": "01a15c60-4e5f-7a6b-8c7d-9e0f1a2b3c4d",
    "title": "Förslag hemstädning",
    "status": "draft",
    "current_version": 1,
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": null,
    "blocks": [
      {
        "type": "heading",
        "attrs": {
          "level": 1
        },
        "content": [
          {
            "type": "text",
            "text": "Hemstäd för familjen Ny"
          }
        ]
      },
      {
        "type": "paragraph",
        "content": [
          {
            "type": "text",
            "text": "Varannan vecka, två timmar per tillfälle."
          }
        ]
      }
    ],
    "settings": [],
    "published_at": null,
    "created_at": "2026-10-12T09:00:00+00:00",
    "updated_at": "2026-10-12T09:00: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.

  • blocksarray of objectsnullable

    The content. Leave out for an empty proposal.

  • settingsobjectnullable

    Display settings used by the editor.

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
      • titlestringrequired
      • statusstringrequired

        draft while being written; in_review when held for approval in the panel; published once released.

        One ofdraftin_reviewpublished

      • current_versionintegerrequired

        Goes up by one with every content change.

        ≥ 1

      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired
      • blocksarray of objectsrequired
      • settingsobject | array of valuesnullablerequired

        Editor display settings. An empty set comes back as [].

        at most 0 items

      • published_atstring(date-time)nullablerequired
      • 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 proposal

GET/proposals/{proposal}

Returns one proposal with its current content.

curl 'https://api.closepact.com/v1/api/proposals/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 200
{
  "data": {
    "id": "01a15c60-4e5f-7a6b-8c7d-9e0f1a2b3c4d",
    "title": "Förslag hemstädning",
    "status": "draft",
    "current_version": 2,
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": null,
    "blocks": [
      {
        "type": "heading",
        "attrs": {
          "level": 1
        },
        "content": [
          {
            "type": "text",
            "text": "Hemstäd för familjen Ny"
          }
        ]
      },
      {
        "type": "bulletList",
        "content": [
          {
            "type": "listItem",
            "content": [
              {
                "type": "paragraph",
                "content": [
                  {
                    "type": "text",
                    "text": "Dammsugning och våttorkning av golv"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "content": [
              {
                "type": "paragraph",
                "content": [
                  {
                    "type": "text",
                    "text": "Rengöring av kök och badrum"
                  }
                ]
              }
            ]
          }
        ]
      }
    ],
    "settings": [],
    "published_at": null,
    "created_at": "2026-10-12T09:00:00+00:00",
    "updated_at": "2026-10-12T10:15:00+00:00"
  }
}

Path parameters

  • proposalstring(uuid)required

    The proposal'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
      • titlestringrequired
      • statusstringrequired

        draft while being written; in_review when held for approval in the panel; published once released.

        One ofdraftin_reviewpublished

      • current_versionintegerrequired

        Goes up by one with every content change.

        ≥ 1

      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired
      • blocksarray of objectsrequired
      • settingsobject | array of valuesnullablerequired

        Editor display settings. An empty set comes back as [].

        at most 0 items

      • published_atstring(date-time)nullablerequired
      • 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

Replace a proposal's content

PATCH/proposals/{proposal}
Scope write Module Proposals & e-signing Permission proposals.create

Replaces the whole block tree — send the complete content, not a change — and saves it as a new version: current_version goes up by one and a snapshot is kept with your notes, under the member the key acts as. The title is not changed here; see Rename a proposal.

The same block checks as on create apply; nothing is saved when one fails. A published proposal can be edited too, and stays published.

curl -X PATCH 'https://api.closepact.com/v1/api/proposals/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "blocks": [
    {
      "type": "heading",
      "attrs": {
        "level": 1
      },
      "content": [
        {
          "type": "text",
          "text": "Hemstäd för familjen Ny"
        }
      ]
    },
    {
      "type": "paragraph",
      "content": [
        {
          "type": "text",
          "text": "Nu med fönsterputs två gånger per år."
        }
      ]
    }
  ],
  "notes": "La till fönsterputs"
}'
Response · 200
{
  "data": {
    "id": "01a15c60-4e5f-7a6b-8c7d-9e0f1a2b3c4d",
    "title": "Förslag hemstädning",
    "status": "draft",
    "current_version": 2,
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": null,
    "blocks": [
      {
        "type": "heading",
        "attrs": {
          "level": 1
        },
        "content": [
          {
            "type": "text",
            "text": "Hemstäd för familjen Ny"
          }
        ]
      },
      {
        "type": "paragraph",
        "content": [
          {
            "type": "text",
            "text": "Nu med fönsterputs två gånger per år."
          }
        ]
      }
    ],
    "settings": [],
    "published_at": null,
    "created_at": "2026-10-12T09:00:00+00:00",
    "updated_at": "2026-10-12T10:15:00+00:00"
  }
}

Path parameters

  • proposalstring(uuid)required

    The proposal's id.

Request body

application/json · required

  • blocksarray of objectsrequired

    at least 1 item

  • notesstringnullable

    What changed, kept with the version.

    at most 255 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
      • titlestringrequired
      • statusstringrequired

        draft while being written; in_review when held for approval in the panel; published once released.

        One ofdraftin_reviewpublished

      • current_versionintegerrequired

        Goes up by one with every content change.

        ≥ 1

      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired
      • blocksarray of objectsrequired
      • settingsobject | array of valuesnullablerequired

        Editor display settings. An empty set comes back as [].

        at most 0 items

      • published_atstring(date-time)nullablerequired
      • 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
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Delete a proposal

DELETE/proposals/{proposal}
Scope write Module Proposals & e-signing Permission proposals.delete

Deletes the proposal: it leaves lists and lookups at once and a later request for it is a 404. No webhook fires.

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

Path parameters

  • proposalstring(uuid)required

    The proposal's id.

Responses

  • 204The proposal 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
  • 429The key has made more requests this minute than its limit allows.
    Errors

Rename a proposal

PATCH/proposals/{proposal}/rename
Scope write Module Proposals & e-signing Permission proposals.create

Changes the title. The content and version are not touched, and no new version is saved.

curl -X PATCH 'https://api.closepact.com/v1/api/proposals/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40/rename' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Förslag hemstäd 2027"
}'
Response · 200
{
  "data": {
    "id": "01a15c60-4e5f-7a6b-8c7d-9e0f1a2b3c4d",
    "title": "Förslag hemstäd 2027",
    "status": "draft",
    "current_version": 2,
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": null,
    "blocks": [
      {
        "type": "paragraph",
        "content": [
          {
            "type": "text",
            "text": "Nu med fönsterputs två gånger per år."
          }
        ]
      }
    ],
    "settings": [],
    "published_at": null,
    "created_at": "2026-10-12T09:00:00+00:00",
    "updated_at": "2026-10-12T10:20:00+00:00"
  }
}

Path parameters

  • proposalstring(uuid)required

    The proposal's id.

Request body

application/json · required

  • titlestringrequired

    1–255 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
      • titlestringrequired
      • statusstringrequired

        draft while being written; in_review when held for approval in the panel; published once released.

        One ofdraftin_reviewpublished

      • current_versionintegerrequired

        Goes up by one with every content change.

        ≥ 1

      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired
      • blocksarray of objectsrequired
      • settingsobject | array of valuesnullablerequired

        Editor display settings. An empty set comes back as [].

        at most 0 items

      • published_atstring(date-time)nullablerequired
      • 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
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors

Publish a proposal

POST/proposals/{proposal}/publish

Marks the proposal published and sets published_at to now; calling it again moves published_at to the new now. Nobody is e-mailed and no webhook fires — to put a proposal in front of a buyer, add it to a room as a proposal content block. No request body.

curl -X POST 'https://api.closepact.com/v1/api/proposals/01a14f2c-7c1e-7d0b-9a3e-3f5b2c8d1e40/publish' \
  -H "Authorization: Bearer $CLOSEPACT_API_KEY"
Response · 200
{
  "data": {
    "id": "01a15c60-4e5f-7a6b-8c7d-9e0f1a2b3c4d",
    "title": "Förslag hemstäd 2027",
    "status": "published",
    "current_version": 2,
    "deal_id": "01a15c2e-4b7a-7f3e-9c1d-2e8f6a0b4c71",
    "deal_room_id": null,
    "blocks": [
      {
        "type": "paragraph",
        "content": [
          {
            "type": "text",
            "text": "Nu med fönsterputs två gånger per år."
          }
        ]
      }
    ],
    "settings": [],
    "published_at": "2026-10-14T07:30:00+00:00",
    "created_at": "2026-10-12T09:00:00+00:00",
    "updated_at": "2026-10-14T07:30:00+00:00"
  }
}

Path parameters

  • proposalstring(uuid)required

    The proposal'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
      • titlestringrequired
      • statusstringrequired

        draft while being written; in_review when held for approval in the panel; published once released.

        One ofdraftin_reviewpublished

      • current_versionintegerrequired

        Goes up by one with every content change.

        ≥ 1

      • deal_idstring(uuid)nullablerequired
      • deal_room_idstring(uuid)nullablerequired
      • blocksarray of objectsrequired
      • settingsobject | array of valuesnullablerequired

        Editor display settings. An empty set comes back as [].

        at most 0 items

      • published_atstring(date-time)nullablerequired
      • 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
  • 422The request body or query failed validation.
    Errors
  • 429The key has made more requests this minute than its limit allows.
    Errors