# Subcontract agreements

An agreement is one of your templates (a subcontract, master service agreement or rate sheet PDF, with the places to sign marked) sent to one subcontractor for electronic signature. They open a private link (no account), fill in their company details, sign, and upload an insurance certificate when the template asks for one. Your company signs too, before or after them. Once both have signed, TruTec assembles the executed copy (the PDF plus a signature and audit page), files it and emails it to the subcontractor.

Templates are set up in TruTec (**Agreements**): uploading the PDF and placing the signature marks needs the editor. The API sends, tracks and signs.

Writes act as the user who created the API key, with that user's estimating role (owner, admin or estimator). A member's key never acts as anyone else: the signing request comes from that user's connected mailbox, and that user is the one who signs for the company.

!!! warning
    `POST /v1/agreement-templates/{id}/send` emails the subcontractor and `POST /v1/agreements/{id}/text-link` texts them. `POST /v1/agreements/{id}/countersign` is a **legal signature in the key creator's name** and, when the subcontractor has already signed, emails them the executed copy. Confirm with the person before calling any of them, especially from an AI assistant.

!!! note
    Partner keys that act on behalf of several workspaces must also pass `firm_id` (query string, or JSON body on writes).

## The agreement object

| Field | Type | Description |
|---|---|---|
| `id` | integer | |
| `name` | string | The template's name when sent. |
| `template_id` | integer | |
| `job_id` | integer or null | |
| `vendor` | object | `id`, `name`, `email`, `phone`. |
| `status` | string | `sent`, `signed` (the subcontractor signed) or `void`. |
| `waiting_on` | string or null | `recipient` (the subcontractor), `company` (you), or `null` when both signed. |
| `fully_executed` | boolean | Both signed. |
| `sent_at`, `viewed_at`, `signed_at` | string or null | |
| `signer` | object or null | Who signed for the subcontractor: `name`, `title`, `company`, `email`, `phone`. |
| `countersigned_at`, `countersigner_name`, `countersigner_title` | | Your company's signature. |
| `insurance_required`, `insurance_received` | boolean | Certificate of insurance. |
| `executed_copy_available` | boolean | The executed PDF exists (download it in TruTec). |
| `company_fields` | array | Single agreement only: your company's marks (`index`, `kind`, `label`, `page`). Text ones are filled when countersigning. |
| `created_at`, `updated_at` | string | |

## Read

`GET /v1/agreement-templates` lists templates: `id`, `name`, `pages`, `ready_to_send` (it has a place for the recipient to sign), `company_signs`, `insurance_required`. **Permission:** Read jobs.

`GET /v1/agreements` lists agreements, newest first. Filters: `vendor_id`, `template_id`, `status`, `updated_after` (then oldest change first), `limit`, `offset`.

`GET /v1/agreements/{id}` returns one.

## Send for signature

`POST /v1/agreement-templates/{template_id}/send`

**Permission:** Write jobs (role: owner, admin or estimator)

**Emails the subcontractor** a "Review and sign" link from the key user's connected mailbox (the system sender otherwise), using the template's cover email. The key user is emailed their own link to sign for the company.

| Name | Type | Description |
|---|---|---|
| `vendor_id` | integer | A subcontractor in your vendor book. |
| `vendor_name`, `vendor_email` | string | Instead of `vendor_id`: adds a new subcontractor and sends to them. With `vendor_id`, `vendor_email` also updates their email. |

```bash
curl -X POST "https://trutec.ai/api/v1/agreement-templates/18/send" \
  -H "X-API-Key: sk_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"vendor_id": 55}'
```

```json
{
  "data": {
    "id": 940, "name": "Master subcontract agreement", "template_id": 18, "job_id": null,
    "vendor": {"id": 55, "name": "Ridge Striping LLC", "email": "office@ridgestriping.example", "phone": null},
    "status": "sent", "waiting_on": "recipient", "fully_executed": false,
    "sent_at": "2026-10-13T17:40:02Z", "viewed_at": null, "signed_at": null, "signer": null,
    "countersigned_at": null, "countersigner_name": null, "countersigner_title": null,
    "insurance_required": true, "insurance_received": false, "executed_copy_available": false,
    "company_fields": [{"index": 3, "kind": "signature", "label": null, "page": 4}],
    "created_at": "2026-10-13T17:40:02Z", "updated_at": "2026-10-13T17:40:02Z"
  },
  "delivered": true,
  "sent_from": "estimating@northgatepaving.example"
}
```

**Errors:** `400` `Place at least one Recipient signature field before sending.` (finish the template in TruTec), `vendor_email is required for a new subcontractor`, `Add an email for this vendor first.` `404` `Agreement template not found`, `Vendor not found`.

## Text the signing link

`POST /v1/agreements/{id}/text-link` with optional `phone` (saved on the vendor first). **Texts the subcontractor** the link from your workspace's texting number. `409` for a withdrawn agreement; `400` when there's no usable cell number or texting isn't set up; `502` when the text could not be sent.

## Sign for your company

`POST /v1/agreements/{id}/countersign`

**Permission:** Write jobs (role: owner, admin or estimator)

Signs as the API key's creator with a typed signature, recorded with the time and the caller's IP address, the same as signing on the page. When the subcontractor has already signed, the executed copy is assembled, filed and **emailed to the subcontractor**. Signing an agreement that is already countersigned changes nothing.

| Name | Type | Required | Description |
|---|---|---|---|
| `name` | string | Yes | The signer's name. |
| `signature_typed` | string | Yes | The signature, typed. |
| `title` | string | No | |
| `initials_typed` | string | When the company has initials marks | |
| `field_values` | object | When the company has text marks | Text by `company_fields` index, e.g. `{"5": "10/13/2026"}`. |

Returns the agreement. **Errors:** `400` `Add your name.`, `Fill in: …`, `This agreement was withdrawn.`

## Delete an unsigned agreement

`DELETE /v1/agreements/{id}`

**Permission:** Write jobs and Delete records (role: owner, admin or estimator)

For a test send, the wrong vendor or a duplicate. Its signing link stops working. An agreement with any signature on it is a legal record and can't be deleted (`409`). Returns `204`.
