Skip to main content

Contracts

The Contracts API provides CRUD access to contracts (signable documents), plus ancillary actions for tags and cloning.
New to the API? Start with Getting started (base URL, response envelope, errors, pagination) and Authentication (API keys). Those conventions apply to every endpoint below and are not repeated here.
Identifier note: contracts are addressed by their numeric doc_id. Wherever {id} appears below it is the doc_id.
Scope: signing (team/client/guest/in-person), publishing & emailing, automation, estimate generation and the rich document editor are managed in-app and are not part of this API. Signature/automation state is exposed read-only where relevant.

The contract object

{
  "id": 136,
  "title": "Service Agreement",
  "status": "draft",
  "value": "5000.00",
  "body": "<p>Agreement terms…</p>",
  "client": { "id": 12, "name": "Acme Inc" },
  "category": { "id": 6, "name": "Standard" },
  "project_id": null,
  "dates": {
    "start": "2026-06-01",
    "end": "2026-12-31",
    "created": "2026-06-17T09:30:00.000000Z",
    "published": null
  },
  "signing": { "client_status": "unsigned", "provider_status": "unsigned" },
  "tags": ["priority"]
}
FieldTypeNotes
idintegerContract id. Used in all URLs.
titlestringContract title.
statusstringRead-only, system-derived: draft, awaiting_signatures, active, expired (driven by signatures + dates).
valuestring|nullContract value.
bodystring|nullContract body (HTML).
clientobject{ id, name }.
categoryobject{ id, name }.
project_idinteger|nullAttached project id (managed in-app).
datesobjectstart, end, created, published.
signingobjectRead-only signing state: client_status, provider_status.
tagsarrayTag titles.

List / search contracts

GET /api/contracts

Query parameters

ParameterTypeDescription
statusstringFilter by status.
client_idintegerFilter by client id.
category_idintegerFilter by category id.
searchstringFree-text search on the title.
sortstringdoc_title, doc_status, doc_date_start, doc_created, doc_value.
orderstringasc or desc (default desc).
limitintegerResults per page (max 100).
pageintegerPage number.

Example request

curl -G https://your-domain/api/contracts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d status=draft -d limit=25
<?php
$query = http_build_query(['status' => 'draft', 'limit' => 25]);
$ch = curl_init("https://your-domain/api/contracts?$query");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

Example response — 200 OK

{
  "data": [ { "id": 136, "title": "Service Agreement", "status": "draft" } ],
  "meta": { "current_page": 1, "per_page": 25, "total": 1, "last_page": 1 },
  "message": "Contracts retrieved successfully."
}

Get a contract

GET /api/contracts/{id}
curl https://your-domain/api/contracts/136 \
  -H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init('https://your-domain/api/contracts/136');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Returns the contract (200) with message “Contract retrieved successfully.”

Create a contract

POST /api/contracts
Creates a contract and its backing estimate record. Provide doc_body to set the content directly, or contract_template to seed the body from a template. (Automation is not configurable via the API; new contracts are created with automation disabled.)

Body parameters

ParameterTypeRequiredNotes
doc_client_idintegeryesExisting client id.
doc_titlestringyes
doc_date_startdateyesYYYY-MM-DD.
doc_categoryidintegeryesExisting (contract) category id.
doc_date_enddatenoMust be on/after the start date.
doc_valuenumericno
doc_project_idintegernoExisting project id.
doc_lead_idintegernoExisting lead id.
doc_bodystring (HTML)noContract content. Overrides contract_template.
contract_templateintegernoTemplate id used to seed the body when doc_body is omitted.

Example request

curl -X POST https://your-domain/api/contracts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d doc_client_id=12 \
  -d doc_title="Service Agreement" \
  -d doc_date_start=2026-06-01 \
  -d doc_categoryid=6
<?php
$ch = curl_init('https://your-domain/api/contracts');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
    CURLOPT_POSTFIELDS     => http_build_query([
        'doc_client_id'  => 12,
        'doc_title'      => 'Service Agreement',
        'doc_date_start' => '2026-06-01',
        'doc_categoryid' => 6,
    ]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

Example response — 201 Created

{
  "data": { "id": 136, "title": "Service Agreement", "status": "draft" },
  "message": "Contract created successfully."
}

Update a contract

PATCH /api/contracts/{id}
ParameterTypeRequiredNotes
doc_titlestringyes
doc_date_startdateyes
doc_categoryidintegeryesExisting category id.
doc_date_enddatenoMust be on/after the start date.
doc_valuenumericno
doc_bodystring (HTML)noReplaces the contract content.
curl -X PATCH https://your-domain/api/contracts/136 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d doc_title="Service Agreement v2" \
  -d doc_date_start=2026-06-01 \
  -d doc_categoryid=6
<?php
$ch = curl_init('https://your-domain/api/contracts/136');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
    CURLOPT_POSTFIELDS     => http_build_query([
        'doc_title'      => 'Service Agreement v2',
        'doc_date_start' => '2026-06-01',
        'doc_categoryid' => 6,
    ]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Returns the contract (200) with message “Contract updated successfully.”

Delete a contract

DELETE /api/contracts/{id}
curl -X DELETE https://your-domain/api/contracts/136 \
  -H "Authorization: Bearer YOUR_API_KEY"

Example response — 200 OK

{
  "data": { "id": 136 },
  "message": "Contract deleted successfully."
}

Set tags

PUT /api/contracts/{id}/tags
The tags array is the full set — it replaces existing tags; an empty array clears them.
ParameterTypeRequiredNotes
tagsarray of stringsyesTag titles. Empty array clears all.
curl -X PUT https://your-domain/api/contracts/136/tags \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d "tags[]=priority"
<?php
$ch = curl_init('https://your-domain/api/contracts/136/tags');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
    CURLOPT_POSTFIELDS     => http_build_query(['tags' => ['priority']]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Returns the contract (200) with message “Contract tags updated successfully.”

Clone a contract

POST /api/contracts/{id}/clone
Creates a new contract from an existing one.
ParameterTypeRequiredNotes
doc_titlestringyesTitle of the new contract.
doc_client_idintegeryesClient for the new contract.
doc_categoryidintegeryesCategory for the new contract.
doc_date_startdateyes
doc_date_enddateno
doc_project_idintegerno
doc_valuenumericno
curl -X POST https://your-domain/api/contracts/136/clone \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d doc_title="Service Agreement (copy)" \
  -d doc_client_id=12 \
  -d doc_categoryid=6 \
  -d doc_date_start=2026-06-01
<?php
$ch = curl_init('https://your-domain/api/contracts/136/clone');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
    CURLOPT_POSTFIELDS     => http_build_query([
        'doc_title'      => 'Service Agreement (copy)',
        'doc_client_id'  => 12,
        'doc_categoryid' => 6,
        'doc_date_start' => '2026-06-01',
    ]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Returns the new contract (201) with message “Contract cloned successfully.”

Errors

See Getting started for the shared error format. Contract-specific:
StatusMeaning
404 Not FoundThe contract id does not exist.
422 Unprocessable EntityValidation failed (e.g. missing client/title/date/category, or an invalid status).
{
  "message": "The given data was invalid.",
  "errors": {
    "doc_client_id": ["The selected doc client id is invalid."],
    "doc_title": ["The doc title field is required."]
  }
}