# Knowify API

> Every Knowify endpoint on Cotlet: inputs, JSON Schema, cURL, Python and Node.js examples and an example response for each call.

Source: https://cotlet.dev/docs/api/knowify

Docs sections: [Get started](https://cotlet.dev/docs.md) · [REST API](https://cotlet.dev/docs/api.md) · [MCP](https://cotlet.dev/docs/mcp.md) · [SDKs & CLI](https://cotlet.dev/docs/sdks.md) · [Integrations](https://cotlet.dev/docs/integrations.md)

15 endpoints for Knowify. Each one is a POST with a JSON body, called with your API key.

- Base URL: `https://cotlet.dev/api/v1/knowify`
- Connects with: Your own Knowify account (admin permissions for costs and invoicing)
- Integration page: https://cotlet.dev/integrations/knowify-api-mcp-server

## Endpoints

| Endpoint | Access | Description |
|---|---|---|
| `list_jobs` | read | Contract jobs with client, contract status, revenue, cost and profitability. |
| `get_job` | read | One job: client, jobsite address, contract style, contract lines, change orders and phases. |
| `get_job_cost` | read | Cost to date vs budget for the job and each phase, from Plan & Track. |
| `list_invoices` | read | Invoices with job, client, amount, balance due and date. |
| `list_clients` | read | Clients with contact email, phone and address. |
| `list_time_entries` | read | Time entries from Review Time: person, job, phase, hours, billable and approval state. |
| `create_client` | write | Add a client to your client list. |
| `create_job` | write | New contract job. It starts as a lead until a proposal is saved. |
| `save_proposal` | write | Save the draft proposal (bid) of a job. The job moves to bidding. Nothing is sent. |
| `send_proposal_for_signature` | write | Email the proposal to the client for e-signature. The job turns active when they sign. |
| `add_change_order` | write | Add a change order to a fixed price job, as a draft or active so it can be invoiced. |
| `create_invoice` | write | Invoice an active job by percent of progress or dollar amount per line, as a draft or finalized. |
| `send_invoice` | write | Email a finalized invoice to the client. |
| `record_payment` | write | Record a full or partial client payment on an invoice. |
| `log_time` | write | Enter hours on a job phase in the Time Tracker and submit them for review. |

## List jobs

`POST https://cotlet.dev/api/v1/knowify/list_jobs`

Access: read.

Returns contract jobs with client, status, revenue, cost and profit. Without a status filter it returns all open jobs, newest first. Search matches job name, client name, address or tag. Use job_id from each item in the other tools.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `status` | enum | no | lead, bidding, out_for_signature, active, rejected or closed. Default: all open. |
| `search` | string | no | Job name, client name, address or tag. |
| `limit` | integer | no | 1 to 100. Default: 25. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/list_jobs \
  -H "Authorization: Bearer $COTLET_API_KEY"
```

**Python**

```python
result = client.call("knowify", "list_jobs")
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'list_jobs');
```

**CLI**

```bash
cotlet call knowify list_jobs
```

### Example response

```json
{
  "jobs": [
    {
      "job_id": "418203",
      "name": "Maple St Remodel",
      "client": "Dana Whitfield",
      "status": "active",
      "contract_style": "fixed_price",
      "revenue": 42400,
      "cost": 22500,
      "profit": 19900
    },
    {
      "job_id": "418410",
      "name": "Riverside Dental Office",
      "client": "Riverside Dental",
      "status": "lead",
      "contract_style": "fixed_price",
      "revenue": 0,
      "cost": 0,
      "profit": 0
    }
  ]
}
```

## Get job

`POST https://cotlet.dev/api/v1/knowify/get_job`

Access: read.

Returns one job with its contract lines, change orders and phases. Contract line and change order IDs go into create_invoice; phase IDs go into log_time. Phases show whether labor is enabled.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | Job ID from list_jobs. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/get_job \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"job_8c41d2"}'
```

**Python**

```python
result = client.call("knowify", "get_job", {"job_id":"job_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'get_job', {"job_id":"job_8c41d2"});
```

**CLI**

```bash
cotlet call knowify get_job --data '{"job_id":"job_8c41d2"}'
```

### Example response

```json
{
  "job_id": "418203",
  "name": "Maple St Remodel",
  "client": {
    "client_id": "cl-2201",
    "name": "Dana Whitfield"
  },
  "jobsite_address": "214 Maple St, Springfield",
  "contract_style": "fixed_price",
  "contract_lines": [
    {
      "line_id": "line-1",
      "description": "Rough-in electrical",
      "price": 22000
    },
    {
      "line_id": "line-2",
      "description": "Fixtures and finish",
      "price": 18000
    }
  ],
  "change_orders": [
    {
      "change_order_id": "co-1",
      "description": "Extra outlets in the kitchen",
      "price": 2400,
      "status": "active"
    }
  ],
  "phases": [
    {
      "phase_id": "ph-1",
      "name": "Framing",
      "labor_enabled": true
    },
    {
      "phase_id": "ph-2",
      "name": "Rough-in",
      "labor_enabled": true
    }
  ]
}
```

## Get job cost

`POST https://cotlet.dev/api/v1/knowify/get_job_cost`

Access: read.

Returns cost to date against budget for the whole job and for each phase, the figures from Plan & Track. Phases over budget have a negative variance. The job totals are the sums of the phases.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | Job ID from list_jobs. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/get_job_cost \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"418203"}'
```

**Python**

```python
result = client.call("knowify", "get_job_cost", {"job_id":"418203"})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'get_job_cost', {"job_id":"418203"});
```

**CLI**

```bash
cotlet call knowify get_job_cost --data '{"job_id":"418203"}'
```

### Example response

```json
{
  "job_id": "418203",
  "budget_total": 29000,
  "cost_total": 22500,
  "phases": [
    {
      "phase": "Framing",
      "budget": 14000,
      "cost": 15200,
      "variance": -1200
    },
    {
      "phase": "Rough-in",
      "budget": 9000,
      "cost": 6100,
      "variance": 2900
    },
    {
      "phase": "Finish",
      "budget": 6000,
      "cost": 1200,
      "variance": 4800
    }
  ]
}
```

## List invoices

`POST https://cotlet.dev/api/v1/knowify/list_invoices`

Access: read.

Returns invoices newest first with job, client, amount, balance due and date. Set unpaid_only to see invoices with a balance due. Use invoice_id in send_invoice and record_payment.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | no | Only invoices of this job. |
| `unpaid_only` | boolean | no | Skip invoices that are fully paid. |
| `since` | date | no | Only invoices dated on or after this date. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/list_invoices \
  -H "Authorization: Bearer $COTLET_API_KEY"
```

**Python**

```python
result = client.call("knowify", "list_invoices")
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'list_invoices');
```

**CLI**

```bash
cotlet call knowify list_invoices
```

### Example response

```json
{
  "invoices": [
    {
      "invoice_id": "90488",
      "job_id": "418120",
      "client": "Riverside Dental",
      "amount": 12500,
      "balance_due": 12500,
      "date": "2026-09-28"
    }
  ]
}
```

## List clients

`POST https://cotlet.dev/api/v1/knowify/list_clients`

Access: read.

Returns clients with contact email, phone and address. Search matches the client name. Use client_id in create_job.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `search` | string | no | Client name. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/list_clients \
  -H "Authorization: Bearer $COTLET_API_KEY"
```

**Python**

```python
result = client.call("knowify", "list_clients")
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'list_clients');
```

**CLI**

```bash
cotlet call knowify list_clients
```

### Example response

```json
{
  "clients": [
    {
      "client_id": "cl-3310",
      "name": "Riverside Dental",
      "email": "office@riverside-dental.example",
      "phone": "555-0142",
      "address": "88 River Rd, Springfield"
    }
  ]
}
```

## List time entries

`POST https://cotlet.dev/api/v1/knowify/list_time_entries`

Access: read.

Returns the time entries you see in Review Time between two dates, with person, job, phase, hours, billable flag and approval state. Filter by job or by approved and unapproved to find entries waiting for review.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | no | Only entries on this job. |
| `from` | date | yes | First day. |
| `to` | date | yes | Last day. |
| `approved` | enum | no | all, approved or unapproved. Default: all. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/list_time_entries \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"2026-10-01","to":"2026-10-01"}'
```

**Python**

```python
result = client.call("knowify", "list_time_entries", {"from":"2026-10-01","to":"2026-10-01"})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'list_time_entries', {"from":"2026-10-01","to":"2026-10-01"});
```

**CLI**

```bash
cotlet call knowify list_time_entries --data '{"from":"2026-10-01","to":"2026-10-01"}'
```

### Example response

```json
{
  "entries": [
    {
      "entry_id": "te-7701",
      "person": "Sam Ortiz",
      "job_id": "418203",
      "phase": "Framing",
      "date": "2026-10-09",
      "hours": 8,
      "billable": true,
      "approved": false
    }
  ]
}
```

## Create client

`POST https://cotlet.dev/api/v1/knowify/create_client`

Access: write.

Adds a client to your client list and returns its client_id for create_job. The email is used for proposals and invoices. It reaches no one, so it runs without asking first.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Client name. |
| `email` | string | no | Contact email, used for proposals and invoices. |
| `phone` | string | no | Contact phone. |
| `address` | string | no | Billing address. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/create_client \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Jane Doe"}'
```

**Python**

```python
result = client.call("knowify", "create_client", {"name":"Jane Doe"})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'create_client', {"name":"Jane Doe"});
```

**CLI**

```bash
cotlet call knowify create_client --data '{"name":"Jane Doe"}'
```

### Example response

```json
{
  "client_id": "cl-3311",
  "name": "Lakeview Dental",
  "email": "office@lakeview-dental.example",
  "status": "created"
}
```

## Create job

`POST https://cotlet.dev/api/v1/knowify/create_job`

Access: write.

Creates a contract job for a client. The job starts as a lead and moves to bidding when save_proposal runs. Contract style is fixed_price or cost_plus. It reaches no one, so it runs without asking first.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes | Job name. |
| `client_id` | string | yes | Client ID from list_clients or create_client. |
| `contract_style` | enum | yes | fixed_price or cost_plus. |
| `jobsite_address` | string | no | Jobsite address. |
| `bid_due_date` | date | no | When the bid is due. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/create_job \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Jane Doe","client_id":"client_8c41d2","contract_style":"fixed_price"}'
```

**Python**

```python
result = client.call("knowify", "create_job", {"name":"Jane Doe","client_id":"client_8c41d2","contract_style":"fixed_price"})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'create_job', {"name":"Jane Doe","client_id":"client_8c41d2","contract_style":"fixed_price"});
```

**CLI**

```bash
cotlet call knowify create_job --data '{"name":"Jane Doe","client_id":"client_8c41d2","contract_style":"fixed_price"}'
```

### Example response

```json
{
  "job_id": "418410",
  "name": "Riverside Dental Office",
  "client_id": "cl-3310",
  "contract_style": "fixed_price",
  "status": "lead"
}
```

## Save proposal

`POST https://cotlet.dev/api/v1/knowify/save_proposal`

Access: write.

Saves the contract lines of the proposal as a draft and moves the job to bidding. Nothing is sent to the client; send_proposal_for_signature does that. It reaches no one, so it runs without asking first.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | Job ID from list_jobs. |
| `line_items` | object | yes | List of { description, price } contract lines. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/save_proposal \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"job_8c41d2","line_items":"line items"}'
```

**Python**

```python
result = client.call("knowify", "save_proposal", {"job_id":"job_8c41d2","line_items":"line items"})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'save_proposal', {"job_id":"job_8c41d2","line_items":"line items"});
```

**CLI**

```bash
cotlet call knowify save_proposal --data '{"job_id":"job_8c41d2","line_items":"line items"}'
```

### Example response

```json
{
  "job_id": "418410",
  "status": "bidding",
  "proposal_total": 38500,
  "line_items": 2
}
```

## Send proposal for signature

`POST https://cotlet.dev/api/v1/knowify/send_proposal_for_signature`

Access: write. Confirm: waits for the user's OK before it runs.

Emails the saved proposal to the client for e-signature. The recipient is the client's contact email unless you pass to_email. The job turns active when the client signs. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | Job ID from list_jobs. |
| `to_email` | string | no | Recipient. Default: the client's contact email. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/send_proposal_for_signature \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"418410","to_email":"pm@riverside-dental.example"}'
```

**Python**

```python
result = client.call("knowify", "send_proposal_for_signature", {"job_id":"418410","to_email":"pm@riverside-dental.example"})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'send_proposal_for_signature', {"job_id":"418410","to_email":"pm@riverside-dental.example"});
```

**CLI**

```bash
cotlet call knowify send_proposal_for_signature --data '{"job_id":"418410","to_email":"pm@riverside-dental.example"}'
```

### Example response

```json
{
  "job_id": "418410",
  "status": "out_for_signature",
  "sent_to": "office@riverside-dental.example"
}
```

## Add change order

`POST https://cotlet.dev/api/v1/knowify/add_change_order`

Access: write.

Adds a change order to a fixed price job. It is a draft unless make_active is true, and only an active change order can be invoiced. It reaches no client, so it runs without asking first.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | Job ID from list_jobs. |
| `description` | string | yes | What changed. |
| `price` | string | yes | Change order price as a decimal, e.g. 2400.00. |
| `make_active` | boolean | no | Make it active right away. Default: false. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/add_change_order \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"job_8c41d2","description":"description","price":"price"}'
```

**Python**

```python
result = client.call("knowify", "add_change_order", {"job_id":"job_8c41d2","description":"description","price":"price"})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'add_change_order', {"job_id":"job_8c41d2","description":"description","price":"price"});
```

**CLI**

```bash
cotlet call knowify add_change_order --data '{"job_id":"job_8c41d2","description":"description","price":"price"}'
```

### Example response

```json
{
  "change_order_id": "co-1",
  "job_id": "418203",
  "description": "Extra outlets in the kitchen",
  "price": 2400,
  "status": "active"
}
```

## Create invoice

`POST https://cotlet.dev/api/v1/knowify/create_invoice`

Access: write. Confirm: waits for the user's OK before it runs.

Invoices an active job by percent of progress or by dollar amount per contract line or change order. It saves a draft unless finalize is true. The invoice amount is the sum of the billed lines. It does not email anyone; send_invoice does. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | Job ID from list_jobs. |
| `method` | enum | yes | percent or amount. |
| `lines` | object | yes | Map of contract line or change order ID to percent or amount to bill. |
| `finalize` | boolean | no | Verify and finalize instead of saving a draft. Default: false. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/create_invoice \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"418203","method":"percent","lines":{"line-1":40,"line-2":40,"co-1":100},"finalize":false}'
```

**Python**

```python
result = client.call("knowify", "create_invoice", {"job_id":"418203","method":"percent","lines":{"line-1":40,"line-2":40,"co-1":100},"finalize":False})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'create_invoice', {"job_id":"418203","method":"percent","lines":{"line-1":40,"line-2":40,"co-1":100},"finalize":false});
```

**CLI**

```bash
cotlet call knowify create_invoice --data '{"job_id":"418203","method":"percent","lines":{"line-1":40,"line-2":40,"co-1":100},"finalize":false}'
```

### Example response

```json
{
  "invoice_id": "90517",
  "job_id": "418203",
  "status": "draft",
  "amount": 18400,
  "balance_due": 18400,
  "date": "2026-10-10"
}
```

## Send invoice

`POST https://cotlet.dev/api/v1/knowify/send_invoice`

Access: write. Confirm: waits for the user's OK before it runs.

Emails a finalized invoice to the client. The recipient is the client's contact email unless you pass to_email. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `invoice_id` | string | yes | Invoice ID from list_invoices or create_invoice. |
| `to_email` | string | no | Recipient. Default: the client's contact email. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/send_invoice \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"invoice_id":"invoice_8c41d2"}'
```

**Python**

```python
result = client.call("knowify", "send_invoice", {"invoice_id":"invoice_8c41d2"})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'send_invoice', {"invoice_id":"invoice_8c41d2"});
```

**CLI**

```bash
cotlet call knowify send_invoice --data '{"invoice_id":"invoice_8c41d2"}'
```

### Example response

```json
{
  "invoice_id": "90517",
  "status": "sent",
  "sent_to": "dana.whitfield@example.com"
}
```

## Record payment

`POST https://cotlet.dev/api/v1/knowify/record_payment`

Access: write. Confirm: waits for the user's OK before it runs.

Records a full or partial client payment on an invoice and returns the new balance due. The memo holds a check number or note. By default you confirm each call; you can switch that off for this tool.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `invoice_id` | string | yes | Invoice ID from list_invoices. |
| `amount` | string | yes | Amount received as a decimal, e.g. 12500.00. |
| `date` | date | yes | Payment date. |
| `memo` | string | no | Check number or note. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/record_payment \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"invoice_id":"invoice_8c41d2","amount":"amount","date":"2026-10-01"}'
```

**Python**

```python
result = client.call("knowify", "record_payment", {"invoice_id":"invoice_8c41d2","amount":"amount","date":"2026-10-01"})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'record_payment', {"invoice_id":"invoice_8c41d2","amount":"amount","date":"2026-10-01"});
```

**CLI**

```bash
cotlet call knowify record_payment --data '{"invoice_id":"invoice_8c41d2","amount":"amount","date":"2026-10-01"}'
```

### Example response

```json
{
  "invoice_id": "90488",
  "amount": 12500,
  "date": "2026-10-09",
  "memo": "Check 4471",
  "balance_due": 0
}
```

## Log time

`POST https://cotlet.dev/api/v1/knowify/log_time`

Access: write.

Enters hours on a job phase in the Time Tracker and submits them for review, where they appear in Review Time. The phase must have labor enabled. It reaches no client, so it runs without asking first.

### Parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `job_id` | string | yes | Job ID from list_jobs. |
| `phase_id` | string | yes | Phase ID from get_job. The phase must have labor enabled. |
| `date` | date | yes | Day worked. |
| `hours` | string | yes | Hours worked as a decimal, e.g. 7.5. |
| `description` | string | no | What was done. |

### Request

**cURL**

```bash
curl -X POST https://cotlet.dev/api/v1/knowify/log_time \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id":"job_8c41d2","phase_id":"phase_8c41d2","date":"2026-10-01","hours":"hours"}'
```

**Python**

```python
result = client.call("knowify", "log_time", {"job_id":"job_8c41d2","phase_id":"phase_8c41d2","date":"2026-10-01","hours":"hours"})
```

**Node.js**

```js
const result = await cotlet.call('knowify', 'log_time', {"job_id":"job_8c41d2","phase_id":"phase_8c41d2","date":"2026-10-01","hours":"hours"});
```

**CLI**

```bash
cotlet call knowify log_time --data '{"job_id":"job_8c41d2","phase_id":"phase_8c41d2","date":"2026-10-01","hours":"hours"}'
```

### Example response

```json
{
  "entry_id": "te-7702",
  "job_id": "418203",
  "phase": "Framing",
  "date": "2026-10-09",
  "hours": 8,
  "status": "submitted"
}
```
