Contracts

Contracts are documents a client reads and signs, such as service agreements and terms of engagement.

A contract is made of ordered sections. A section is either freeform text, stored as Quill delta operations, or a fees section: one or more priced packages the client sees and, when the section allows a choice, picks from. Any section may require the client's signature.

Get Contracts

GET /api/v2/contracts

Accepts status (draft, sent, viewed, signed, voided), from_date, and to_date, by contract date.

Templates are not included; only contracts issued to clients. Each row carries its sections, as in the single-contract response below.

{
  "total_count": 3,
  "page_count": 1,
  "page_size": 20,
  "contracts": [
    {
      "id": 1,
      "subject": "Lawn refresh agreement",
      "status": "draft",
      "date": "2026-09-11",
      "client_id": 12,
      "project_id": null,
      "created_at": "2026-09-11T16:10:59Z",
      "updated_at": "2026-09-11T16:10:59Z"
    },
    ...
  ]
}
GET /api/v2/clients/:client_id/contracts

Contracts are also a nested resource for Clients

Get A Contract

GET /api/v2/contracts/:id

url is the contract in the app. client_view_url is the client's own view, no login needed, and pdf_url is its PDF. Both keyed links can be shared as they stand.

{
  "id": 1,
  "subject": "Lawn refresh agreement",
  "status": "draft",
  "date": "2026-09-11",
  "client_id": 12,
  "url": "https://yourdomain.clientary.com/contracts/1",
  "client_view_url": "https://yourdomain.clientary.com/contracts/1/client_view/k-abc123",
  "pdf_url": "https://yourdomain.clientary.com/contracts/1/pdf/k-abc123.pdf",
  "contract_sections": [
    {
      "id": 10,
      "position": 0,
      "section_type": "freeform",
      "content": [
        { "insert": "Scope" },
        { "insert": "\n", "attributes": { "header": 2 } },
        { "insert": "Remove old sod and lay new turf.\n" }
      ]
    },
    {
      "id": 11,
      "position": 1,
      "section_type": "fees",
      "content": {
        "type": "static",
        "title": "Fee",
        "instructions": [ { "insert": "\n" } ],
        "options": [
          {
            "title": "",
            "description": "",
            "line_items": [
              { "item_type": "service", "title": "Lawn refresh", "quantity": 1, "price": 5000, "taxable": false }
            ]
          }
        ]
      }
    }
  ]
}

Create A New Contract

POST /api/v2/contracts
{
  "contract": {
    "client_id": 12,
    "subject": "Lawn refresh agreement",
    "date": "2026-09-11",
    "contract_sections_attributes": [
      {
        "position": 0,
        "section_type": "freeform",
        "content": [ { "insert": "Remove old sod and lay new turf.\n" } ]
      },
      {
        "position": 1,
        "section_type": "fees",
        "content": {
          "type": "static",
          "title": "Fee",
          "instructions": [ { "insert": "\n" } ],
          "options": [
            {
              "line_items": [
                { "item_type": "service", "title": "Lawn refresh", "quantity": 1, "price": 5000, "taxable": false }
              ]
            }
          ]
        }
      }
    ]
  }
}

Required Fields: client_id, date, and at least one section or a template_id (HTTP 422 on failure)
From a template: pass template_id beside the document to start from one of the account's templates or a built-in default. See Templates.
Optional Fields: settings_auto_create_invoice_after_sign - when the client signs, an invoice for what they chose is created and sent to them automatically

Freeform sections

content is an array of Quill delta operations. Plain text is one insert ending in a newline. A wrapped form, { "ops": [...] }, is accepted as well.

Fees sections

content is an object:

type: static shows the packages. single lets the client choose one package; multi lets them choose several. Both choice types need at least two options, each with a title.
title: Heading shown above the packages.
instructions: Quill delta operations shown above the packages; [ { "insert": "\n" } ] for none.
options: The packages. Each has an optional title and description and a required line_items array.
line_items[].item_type: service for a priced line, header for a label with no amount.
line_items[].title: Required.
line_items[].quantity, price: Required for a service line.
line_items[].taxable: Required, true or false.

A package may also carry currency_code, tax, tax_label, tax2, tax2_label, tax2_enabled, and compound_tax.

Update A Contract

PUT /api/v2/contracts/:id

You may provide a partial list of fields to update. Sections are updated through contract_sections_attributes: include an id to change an existing section, omit it to add one, or send "_destroy": true with an id to remove one. A contract the client has signed can no longer be changed.

{
  "contract": {
    "subject": "Lawn refresh agreement, revised",
    "contract_sections_attributes": [
      { "id": 10, "_destroy": true },
      { "position": 0, "section_type": "freeform", "content": [ { "insert": "Revised scope.\n" } ] }
    ]
  }
}

Delete A Contract

DELETE /api/v2/contracts/:id

Deletions are permanent and not reversible.

Send A Contract

POST /api/v2/contracts/:id/messages
{
  "recipients": ["abc@example.com", "xyz@example.com"],
  "subject": "Subject for the contract",
  "message": "Body message for the contract",
  "send_copy": 1,
  "attach_pdf": 1
}

Required Fields: recipients - an array of email addresses. (HTTP 422 on failure)
Encouraged Fields: subject, message are strongly encouraged, since this is what displays in the email, but it is not required.
Optional Fields: send_copy optionally allows the sending user (dependent on API Token used) to receive a copy of the email, attach_pdf allows an optional PDF to be attached.

An address that is not yet a contact of the client becomes one. Each recipient gets their own link to view and sign it. Sending marks the contract sent.