{
    "openapi": "3.0.3",
    "info": {
        "title": "Couplr API",
        "version": "1.2.0",
        "description": "Read and write a company's customers and jobs, and read its invoices,\nestimates and leads.\n\n**Authentication.** Send a company API key as `Authorization: Bearer hvp_\u2026`\n(or `X-Api-Key: hvp_\u2026`). An admin creates keys on the Integrations page;\nthe key is shown once. Each key carries a list of abilities\n(`customers:read`, `jobs:write`, \u2026) and can only call the endpoints those\nabilities cover. A key only ever sees its own company's records: an id\nthat belongs to another company is a `404`.\n\n**Versioning.** `/api/v1` changes additively only: new endpoints, new\noptional request fields, new response fields. Clients must ignore response\nfields they do not know. Anything breaking ships under a new prefix.\n\n**Pagination.** List endpoints take `page` (from 1) and `per_page`\n(default 25, values above 100 are served as 100) and return `meta` with\n`page`, `per_page`, `total`, `last_page`. Lists are ordered newest first\nwith the id as the final sort, so walking the pages never skips or repeats\na row unless records are created or deleted while you walk.\n\n**Rate limits.** 120 requests a minute per API key. Every response carries\n`X-RateLimit-Limit` and `X-RateLimit-Remaining`; a `429` adds\n`Retry-After` (seconds). Wait that long, then retry. Requests with no key\nor an invalid key are limited to 60 a minute per IP address.\n\n**Retries and idempotency.** `GET` is always safe to retry. For `POST` and\n`PATCH` send an `Idempotency-Key` header (any string up to 100 characters,\nunique per operation, e.g. a UUID). A repeat of the same key on the same\nendpoint within 7 days returns the first response, marked\n`Idempotent-Replayed: true`, without running again. `5xx` responses are\nnot remembered, so they can be retried with the same key. Retry `429` and\n`5xx` with exponential backoff and jitter; do not retry other `4xx`.\n\n**Errors.** Error bodies are RFC 9457 problem details (`type`, `title`,\n`status`, `detail`) with a stable machine-readable `code` and the\n`request_id` to give to support. `message` repeats `detail`, and a `422`\nlists per-field messages under `errors`. Bodies are served as\n`application/json`; send `Accept: application/problem+json` to receive the\nregistered media type.\n\n**Field conventions.** A request field you omit is left unchanged\n(`PATCH`) or takes its default (`POST`). Request fields that are not\ndocumented here are ignored. Timestamps are ISO 8601 in UTC unless a field\nsays otherwise; dates are `YYYY-MM-DD`. Customer and job ids are integers;\ninvoice ids are UUID strings. Money is in US dollars: invoice `amount` and\nline `rate` are decimal strings (`\"125.00\"`), estimate `total` is a number.\n\n**Outbound webhooks** are configured on the Integrations page. Each\ndelivery is a `POST` with `X-Hvacpro-Event` and `X-Hvacpro-Signature`, the\nhex HMAC-SHA256 of the raw request body under the subscription's secret.\nVerify the signature over the raw bytes before parsing, with a\nconstant-time compare. Deliveries are retried up to 4 times (after 1, 5\nand 15 minutes) until you answer `2xx`, so the same event can arrive more\nthan once and out of order: dedupe on the body's `id`.\n"
    },
    "servers": [
        {
            "url": "/api/v1"
        }
    ],
    "security": [
        {
            "apiKey": []
        }
    ],
    "tags": [
        {
            "name": "Customers",
            "description": "List, find, create and update customers, and add service addresses to them."
        },
        {
            "name": "Jobs",
            "description": "List, create and update jobs."
        },
        {
            "name": "Lookup lists",
            "description": "Short lists of the job types, technicians, tags, lead sources and market segments a job refers to by id."
        },
        {
            "name": "Invoices",
            "description": "List and read invoices with their line items, and create draft invoices."
        },
        {
            "name": "Payments",
            "description": "Read the payments collected on invoices and what has been refunded."
        },
        {
            "name": "Price book",
            "description": "List, read, create and update the items a company puts on invoices and estimates."
        },
        {
            "name": "Estimates",
            "description": "List and read estimates, create one with the simple layout, and email it to the customer."
        },
        {
            "name": "Schedules and time",
            "description": "Read time entries (who worked when) and the schedule blocks that are not jobs."
        },
        {
            "name": "Notes",
            "description": "Read the notes on a customer or a job, and add a note."
        },
        {
            "name": "Photos and documents",
            "description": "Time-limited links to the photos on a job or a customer, and to a customer's documents."
        },
        {
            "name": "Equipment",
            "description": "Read the equipment installed at a customer's addresses."
        },
        {
            "name": "Booking",
            "description": "Find open time slots and book a visit into one."
        },
        {
            "name": "Maintenance plans",
            "description": "Read the maintenance plans a company sells and which customers are enrolled in them, and enroll a customer."
        },
        {
            "name": "Leads",
            "description": "List and read the leads Couplr's assistant is talking to, and add a lead."
        },
        {
            "name": "Webhook subscriptions",
            "description": "Add, change and remove the destinations Couplr sends events to."
        },
        {
            "name": "Deleted records",
            "description": "Learn which customers, jobs, invoices and estimates were removed, to keep a copy in step."
        },
        {
            "name": "Account",
            "description": "Identify the API key in use."
        }
    ],
    "paths": {
        "/me": {
            "get": {
                "tags": [
                    "Account"
                ],
                "operationId": "getMe",
                "summary": "Identify the API key",
                "description": "Works with any valid key. Use it to test a connection.",
                "responses": {
                    "200": {
                        "description": "The key's company, name and abilities.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "company",
                                        "key_name",
                                        "abilities",
                                        "test_mode"
                                    ],
                                    "properties": {
                                        "company": {
                                            "type": "string"
                                        },
                                        "key_name": {
                                            "type": "string"
                                        },
                                        "abilities": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Ability"
                                            }
                                        },
                                        "test_mode": {
                                            "type": "boolean",
                                            "description": "True when the key belongs to a test sandbox, not to the live account."
                                        }
                                    }
                                },
                                "example": {
                                    "company": "Summit Heat and Air",
                                    "key_name": "Zapier",
                                    "abilities": [
                                        "customers:read",
                                        "customers:write"
                                    ],
                                    "test_mode": false
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/deleted": {
            "get": {
                "tags": [
                    "Deleted records"
                ],
                "operationId": "listDeleted",
                "summary": "List deleted records",
                "description": "The ids of customers, jobs, invoices and estimates that were removed\nin Couplr at or after `since`, most recently removed first. Lists and\n`updated_since` only return records that still exist, so use this to\nremove them from your own copy.\n\nIt needs no ability of its own. A key is shown removals for the kinds\nof record it can read: `customers:read`, `jobs:read`, `invoices:read`\nand `estimates:read`. Asking for a `type` the key cannot read, or\nholding none of the four, is a `403`.\n\nA removed record is reported for as long as Couplr keeps it in its\nTrash. One that is restored stops being listed and comes back in its\nown list with a new `updated_at`. This endpoint only reports. Nothing\ncan be deleted through the API.\n",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "name": "since",
                        "in": "query",
                        "required": true,
                        "description": "Only records removed at or after this time. ISO 8601.",
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "customer",
                                "job",
                                "invoice",
                                "estimate"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of removed records, most recently removed first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/DeletedRecord"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/customers": {
            "get": {
                "tags": [
                    "Customers"
                ],
                "operationId": "listCustomers",
                "summary": "List customers",
                "x-required-ability": "customers:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "search",
                        "in": "query",
                        "description": "Matches part of a name, alternate name, email or phone.",
                        "schema": {
                            "type": "string",
                            "maxLength": 255
                        }
                    },
                    {
                        "name": "email",
                        "in": "query",
                        "description": "Exact email match.",
                        "schema": {
                            "type": "string",
                            "maxLength": 255
                        }
                    },
                    {
                        "name": "phone",
                        "in": "query",
                        "description": "Matches part of the phone number; non-digits are ignored.",
                        "schema": {
                            "type": "string",
                            "maxLength": 50
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of customers, newest first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Customer"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "tags": [
                    "Customers"
                ],
                "operationId": "createCustomer",
                "summary": "Create a customer",
                "x-required-ability": "customers:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CustomerCreate"
                            },
                            "example": {
                                "name": "Dana Whitfield",
                                "email": "dana@example.com",
                                "phone": "(555) 201-8890",
                                "address": "412 Larkspur Ln",
                                "city": "Tulsa",
                                "state": "OK",
                                "zip_code": "74105"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The created customer.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Customer"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "409": {
                        "description": "Only when `ignore_duplicates` is `false`: a customer with the same\nname or address exists. The body lists up to 5 candidates under\n`duplicates`, each a Customer plus `matched_on` (what collided).\nNothing was created.\n",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "allOf": [
                                        {
                                            "$ref": "#/components/schemas/Problem"
                                        },
                                        {
                                            "type": "object",
                                            "required": [
                                                "duplicates"
                                            ],
                                            "properties": {
                                                "duplicates": {
                                                    "type": "array",
                                                    "items": {
                                                        "allOf": [
                                                            {
                                                                "$ref": "#/components/schemas/Customer"
                                                            },
                                                            {
                                                                "type": "object",
                                                                "required": [
                                                                    "matched_on"
                                                                ],
                                                                "properties": {
                                                                    "matched_on": {
                                                                        "type": "array",
                                                                        "items": {
                                                                            "type": "string",
                                                                            "enum": [
                                                                                "name",
                                                                                "address"
                                                                            ]
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        ]
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "422": {
                        "description": "Validation failed, including an email (or, with\n`uses_email: false`, a phone) that already belongs to another\ncustomer.\n",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/Problem"
                                }
                            }
                        }
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/customers/{id}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "get": {
                "tags": [
                    "Customers"
                ],
                "operationId": "getCustomer",
                "summary": "Get a customer",
                "x-required-ability": "customers:read",
                "responses": {
                    "200": {
                        "description": "The customer.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Customer"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Customers"
                ],
                "operationId": "updateCustomer",
                "summary": "Update a customer",
                "description": "Only the fields you send change.",
                "x-required-ability": "customers:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/CustomerUpdate"
                            },
                            "example": {
                                "phone": "(555) 201-7700"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated customer.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Customer"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/customers/{id}/addresses": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "post": {
                "tags": [
                    "Customers"
                ],
                "operationId": "addCustomerAddress",
                "summary": "Add an address to a customer",
                "description": "Adds another service address, such as a rental or a second property. Use its id as `address_id` when creating a job.",
                "x-required-ability": "customers:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/AddressCreate"
                            },
                            "example": {
                                "address": "88 Rental Row",
                                "city": "Tulsa",
                                "state": "OK",
                                "zip_code": "74104"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new address.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Address"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/jobs": {
            "get": {
                "tags": [
                    "Jobs"
                ],
                "operationId": "listJobs",
                "summary": "List jobs",
                "x-required-ability": "jobs:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "customer_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "description": "`open` or `completed`. Any other value is ignored.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "open",
                                "completed"
                            ]
                        }
                    },
                    {
                        "name": "scheduled_from",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "scheduled_to",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of jobs, latest scheduled date first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Job"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "tags": [
                    "Jobs"
                ],
                "operationId": "createJob",
                "summary": "Create a job",
                "description": "Creating a job behaves as it does in the app: it appears on the\nschedule, may be auto-dispatched to a technician, and fires the\n`job.created` webhook. A second identical request (same customer, job\ntype and day) within 30 seconds returns the first job with `201`\nrather than creating another; send an `Idempotency-Key` for a longer\nwindow.\n",
                "x-required-ability": "jobs:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/JobCreate"
                            },
                            "example": {
                                "customer_id": 1842,
                                "job_type": "Repair",
                                "scheduled_date": "2026-12-02",
                                "scheduled_start_time": "09:00",
                                "notes": "No cooling upstairs. Gate code 4410."
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The created job.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Job"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/jobs/{id}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "get": {
                "tags": [
                    "Jobs"
                ],
                "operationId": "getJob",
                "summary": "Get a job",
                "x-required-ability": "jobs:read",
                "responses": {
                    "200": {
                        "description": "The job.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Job"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Jobs"
                ],
                "operationId": "updateJob",
                "summary": "Update a job",
                "description": "Reschedule a job, move it to another of the customer's addresses,\nchange the crew or edit its notes. Only the fields you send change.\nThe customer cannot be changed. A job is completed with\n`POST /jobs/{id}/complete` and cannot be deleted through the API.\n",
                "x-required-ability": "jobs:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/JobUpdate"
                            },
                            "example": {
                                "scheduled_date": "2026-12-04",
                                "scheduled_start_time": "13:00"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated job.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Job"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/jobs/{id}/complete": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "post": {
                "tags": [
                    "Jobs"
                ],
                "operationId": "completeJob",
                "summary": "Complete a job",
                "description": "Marks a job done, the same as completing it in the apps. The\n`job.completed` event is delivered (`estimate.completed` for an\nestimate visit) and the crew is credited for the work.\n\n**The customer may be contacted.** Completing a job sends whatever\nthe company has switched on for a finished job: the completion text\nand, if the company asks for reviews automatically, a review\nrequest. That is why this has its own ability.\n\n`notes`, if sent, is added to the job's notes log.\n\nRefused with `422` on `job` when the job is already completed; when\nit is a maintenance plan visit; when an invoice is being held until\nthe job is done; or when the job type has a checklist that must be\nfilled in. Complete those in Couplr.\n",
                "x-required-ability": "jobs:complete",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": false,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/JobComplete"
                            },
                            "example": {
                                "notes": "Replaced the capacitor. System cooling normally."
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The completed job.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Job"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/job-types": {
            "get": {
                "tags": [
                    "Lookup lists"
                ],
                "operationId": "listJobTypes",
                "summary": "List job types",
                "description": "The company's job types, by name. Not paginated.",
                "x-required-ability": "jobs:read",
                "responses": {
                    "200": {
                        "description": "Every job type.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "required": [
                                                    "id",
                                                    "name"
                                                ],
                                                "properties": {
                                                    "id": {
                                                        "type": "integer"
                                                    },
                                                    "name": {
                                                        "type": "string"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/technicians": {
            "get": {
                "tags": [
                    "Lookup lists"
                ],
                "operationId": "listTechnicians",
                "summary": "List technicians",
                "description": "Technicians a job can be assigned to. Use an id as `assigned_tech_id`, in `assigned_tech_ids` or as `lead_tech_id`. Not paginated.",
                "x-required-ability": "jobs:read",
                "responses": {
                    "200": {
                        "description": "The whole list.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/NamedItem"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/tags": {
            "get": {
                "tags": [
                    "Lookup lists"
                ],
                "operationId": "listTags",
                "summary": "List tags",
                "description": "Tags that can be put on a job with `tag_ids`. Not paginated.",
                "x-required-ability": "jobs:read",
                "responses": {
                    "200": {
                        "description": "The whole list.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/NamedItem"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/lead-sources": {
            "get": {
                "tags": [
                    "Lookup lists"
                ],
                "operationId": "listLeadSources",
                "summary": "List lead sources",
                "description": "Where customers come from. Use an id as `lead_source_id`. Not paginated.",
                "x-required-ability": "jobs:read",
                "responses": {
                    "200": {
                        "description": "The whole list.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/NamedItem"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/market-segments": {
            "get": {
                "tags": [
                    "Lookup lists"
                ],
                "operationId": "listMarketSegments",
                "summary": "List market segments",
                "description": "The company's market segments. Use an id as `market_segment_id`. Not paginated.",
                "x-required-ability": "jobs:read",
                "responses": {
                    "200": {
                        "description": "The whole list.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/NamedItem"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/invoices": {
            "get": {
                "tags": [
                    "Invoices"
                ],
                "operationId": "listInvoices",
                "summary": "List invoices",
                "x-required-ability": "invoices:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "description": "Exact status match, e.g. `paid`.",
                        "schema": {
                            "type": "string",
                            "maxLength": 50
                        }
                    },
                    {
                        "name": "customer_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "created_from",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "created_to",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of invoices, newest first. No line items.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Invoice"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "tags": [
                    "Invoices"
                ],
                "operationId": "createInvoiceDraft",
                "summary": "Create a draft invoice",
                "description": "Creates an invoice with status `draft`. Nothing is sent to the\ncustomer and nothing is charged. The draft appears in Couplr, where\nsomeone reviews it and sends it, or you send it with\n`POST /invoices/{id}/send`. An invoice cannot be marked as paid or\ncharged through the API.\n\nA line with `price_book_item_id` uses that price book item. A line\nwithout one is matched to a price book item with the same name, or\nadded to the price book as a new item. A job can have one draft:\ncreating another for the same job replaces the first.\n",
                "x-required-ability": "invoices:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/InvoiceDraftCreate"
                            },
                            "example": {
                                "customer_id": 1842,
                                "job_id": 9312,
                                "notes": "Replaced condenser fan motor.",
                                "line_items": [
                                    {
                                        "name": "Condenser fan motor",
                                        "quantity": 1,
                                        "unit_price": 289
                                    },
                                    {
                                        "name": "Service call",
                                        "quantity": 1,
                                        "unit_price": 100
                                    }
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The draft invoice with its line items.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Invoice"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/invoices/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Invoices"
                ],
                "operationId": "getInvoice",
                "summary": "Get an invoice",
                "description": "Includes `line_items`.",
                "x-required-ability": "invoices:read",
                "responses": {
                    "200": {
                        "description": "The invoice with its line items.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Invoice"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/invoices/{id}/send": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "post": {
                "tags": [
                    "Invoices"
                ],
                "operationId": "sendInvoice",
                "summary": "Send a draft invoice",
                "description": "Sends a draft invoice to the customer by email with Couplr's payment\nlink, the same as \"Send invoice\" in the apps. The customer pays\nthrough that link. Nothing is charged by this call, and there is no\nway to record a payment made any other way.\n\nA draft that was saved in Couplr as a bank-only or a financing\ninvoice is sent that way, and a deposit already credited on the\ndraft stays on it. You cannot choose how the customer pays or set a\ndeposit.\n\nThere is no request body. The draft is sent as it stands: its\nquantities, prices, notes and extra recipients are not changed. Each\nline goes out under its price book item's current name, and sales tax\nis worked out again from the account's current tax settings, as it is\nwhenever an invoice is sent from Couplr. Read `amount` in the\nresponse for the amount billed.\n\nThe response has status `processing` while Couplr prepares the\npayment link. A moment later the invoice becomes `sent`,\n`hosted_invoice_url` is filled in and the `invoice.sent` event is\ndelivered.\n\nRefused with `422` on `invoice` when: the invoice is not a draft; the\ncustomer has no email address; online payments are not set up for the\naccount; or the draft was set up in Couplr with a payment option the\nAPI does not send (a charge to a saved card, or split payments); a\nline uses a price book item that has\nbeen archived; or another send of the same invoice is in progress.\nSend those from Couplr.\n",
                "x-required-ability": "invoices:send",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The invoice, now being sent, with its line items.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Invoice"
                                        }
                                    }
                                },
                                "example": {
                                    "data": {
                                        "id": "9d3f6a52-0c1e-4c57-9d0a-3a0f8a4a7b21",
                                        "invoice_number": "1047",
                                        "customer_id": 1842,
                                        "customer_name": "Dana Whitfield",
                                        "job_id": 9312,
                                        "status": "processing",
                                        "amount": "389.00",
                                        "notes": "Replaced condenser fan motor.",
                                        "hosted_invoice_url": null,
                                        "created_at": "2026-12-02T17:20:05+00:00",
                                        "updated_at": "2026-12-02T18:01:44+00:00",
                                        "line_items": [
                                            {
                                                "name": "Condenser fan motor",
                                                "quantity": 1,
                                                "rate": "289.00"
                                            },
                                            {
                                                "name": "Service call",
                                                "quantity": 1,
                                                "rate": "100.00"
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/invoices/{id}/payments": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Payments"
                ],
                "operationId": "listInvoicePayments",
                "summary": "List an invoice's payments",
                "description": "Every payment collected on one invoice, oldest first. Not paginated.",
                "x-required-ability": "payments:read",
                "responses": {
                    "200": {
                        "description": "The invoice's payments. An empty list when nothing has been paid.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Payment"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/payments": {
            "get": {
                "tags": [
                    "Payments"
                ],
                "operationId": "listPayments",
                "summary": "List payments",
                "description": "Payments collected on the company's invoices, most recently paid\nfirst. `updated_since` also returns a payment whose invoice changed,\nso a refund brings the payment back.\n",
                "x-required-ability": "payments:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "invoice_id",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "uuid"
                        }
                    },
                    {
                        "name": "customer_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "method",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "card",
                                "bank",
                                "financing",
                                "cash",
                                "check",
                                "other"
                            ]
                        }
                    },
                    {
                        "name": "paid_from",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "paid_to",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of payments, most recently paid first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Payment"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/price-book-items": {
            "get": {
                "tags": [
                    "Price book"
                ],
                "operationId": "listPriceBookItems",
                "summary": "List price book items",
                "description": "The company's active items, in name order. Archived items and the lines Couplr adds itself, such as sales tax, are not listed.",
                "x-required-ability": "price-book:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "search",
                        "in": "query",
                        "description": "Matches part of the name or part number.",
                        "schema": {
                            "type": "string",
                            "maxLength": 255
                        }
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "equipment",
                                "labor",
                                "material",
                                "fee"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of price book items, in name order.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/PriceBookItem"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "tags": [
                    "Price book"
                ],
                "operationId": "createPriceBookItem",
                "summary": "Create a price book item",
                "description": "Adds an item to the price book. Names are not required to be unique,\nso check the list first if you do not want two items with one name.\n",
                "x-required-ability": "price-book:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/PriceBookItemCreate"
                            },
                            "example": {
                                "name": "Condenser fan motor",
                                "description": "1/4 HP, 825 RPM, universal fit.",
                                "type": "material",
                                "unit_price": 289,
                                "part_number": "FM-2500"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new item.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/PriceBookItem"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/price-book-items/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "integer"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Price book"
                ],
                "operationId": "getPriceBookItem",
                "summary": "Get a price book item",
                "x-required-ability": "price-book:read",
                "responses": {
                    "200": {
                        "description": "The item.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/PriceBookItem"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "patch": {
                "tags": [
                    "Price book"
                ],
                "operationId": "updatePriceBookItem",
                "summary": "Update a price book item",
                "description": "Only the fields you send change. A new price applies to invoices and\nestimates written from then on; ones already written keep the price\nthey were written with. An item's `type` cannot be changed here.\n",
                "x-required-ability": "price-book:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/PriceBookItemUpdate"
                            },
                            "example": {
                                "unit_price": 305
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated item.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/PriceBookItem"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/estimates": {
            "get": {
                "tags": [
                    "Estimates"
                ],
                "operationId": "listEstimates",
                "summary": "List estimates",
                "x-required-ability": "estimates:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "customer_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "description": "`open`, `accepted` or `declined`. Any other value is ignored.",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "open",
                                "accepted",
                                "declined"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of estimates, newest first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Estimate"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "tags": [
                    "Estimates"
                ],
                "operationId": "createEstimate",
                "summary": "Create an estimate",
                "description": "Creates an estimate with the `simple` layout: one list of items. It\nis a draft unless you send `\"send\": true`, in which case Couplr\nemails it to the customer as soon as it is ready. The customer reads\nand accepts it on Couplr's page. Nothing is charged.\n\nA line with `price_book_item_id` uses that price book item and its\nname. A line without one uses the price book item of the same name,\nor adds the name to the price book as a new item. An item can appear\nonce: for two of the same thing, send one line with a quantity.\n\nDiscounts, deposits, maintenance plans and the `sectioned` layout\nare set in Couplr and cannot be created here. Sales tax follows the\naccount's tax settings.\n",
                "x-required-ability": "estimates:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/EstimateCreate"
                            },
                            "example": {
                                "customer_id": 1842,
                                "title": "New condenser fan motor",
                                "notes": "Price includes disposal of the old motor.",
                                "line_items": [
                                    {
                                        "name": "Condenser fan motor",
                                        "quantity": 1,
                                        "unit_price": 289
                                    },
                                    {
                                        "price_book_item_id": 771,
                                        "quantity": 1
                                    }
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The estimate with its line items.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Estimate"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/estimates/{id}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "get": {
                "tags": [
                    "Estimates"
                ],
                "operationId": "getEstimate",
                "summary": "Get an estimate",
                "x-required-ability": "estimates:read",
                "responses": {
                    "200": {
                        "description": "The estimate.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Estimate"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/estimates/{id}/send": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "post": {
                "tags": [
                    "Estimates"
                ],
                "operationId": "sendEstimate",
                "summary": "Send an estimate",
                "description": "Emails the estimate to its customer, the same as \"Send\" in the apps.\nThere is no request body. An estimate can be sent more than once.\n\nEither layout can be sent. A `sectioned` estimate also goes to the\nextra recipients saved on it in Couplr, and its `status` can still\nread `draft` afterwards.\n\nRefused with `422` on `estimate` when: it has already been\naccepted or declined; the customer has no email address; or it was\ncreated a moment ago and is still being prepared, in which case try\nagain shortly.\n",
                "x-required-ability": "estimates:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "The estimate, now sent.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Estimate"
                                        }
                                    }
                                },
                                "example": {
                                    "data": {
                                        "id": 511,
                                        "layout": "simple",
                                        "title": "New condenser fan motor",
                                        "customer_id": 1842,
                                        "customer_name": "Dana Whitfield",
                                        "status": "sent",
                                        "total": 389,
                                        "accepted_at": null,
                                        "declined_at": null,
                                        "created_at": "2026-11-30T14:10:00+00:00",
                                        "updated_at": "2026-11-30T14:12:00+00:00",
                                        "line_items": [
                                            {
                                                "name": "Condenser fan motor",
                                                "quantity": 1,
                                                "rate": "289.00"
                                            },
                                            {
                                                "name": "Service call",
                                                "quantity": 1,
                                                "rate": "100.00"
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/time-entries": {
            "get": {
                "tags": [
                    "Schedules and time"
                ],
                "operationId": "listTimeEntries",
                "summary": "List time entries",
                "description": "Each time someone clocked in, most recent first: on a job, or on\nother paid time such as the shop or training. Hours only. Pay rates\nand payroll figures are not available through the API.\n",
                "x-required-ability": "timesheets:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "technician_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "job_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "job",
                                "shift"
                            ]
                        }
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "description": "Clocked in at or after this time.",
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "description": "Clocked in at or before this time.",
                        "schema": {
                            "type": "string",
                            "format": "date-time"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of time entries, most recent first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/TimeEntry"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/schedule-events": {
            "get": {
                "tags": [
                    "Schedules and time"
                ],
                "operationId": "listScheduleEvents",
                "summary": "List schedule events",
                "description": "Blocks on the schedule that are not jobs: time off, meetings and\nheld slots. Most recent date first. Jobs are read with the Jobs\nendpoints.\n",
                "x-required-ability": "timesheets:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "technician_id",
                        "in": "query",
                        "description": "Events for this person, and events for the whole company.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "kind",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "time_off",
                                "meeting",
                                "hold",
                                "other"
                            ]
                        }
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of schedule events, most recent date first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/ScheduleEvent"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/customers/{id}/notes": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "get": {
                "tags": [
                    "Notes"
                ],
                "operationId": "listCustomerNotes",
                "summary": "List a customer's notes",
                "description": "The notes written on the customer, newest first.",
                "x-required-ability": "notes:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of notes, newest first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Note"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "tags": [
                    "Notes"
                ],
                "operationId": "createCustomerNote",
                "summary": "Add a note to a customer",
                "description": "The note is added to the log under the name of the person who\ncreated the API key. A note cannot be edited or removed through the\nAPI.\n\nSend `\"is_private\": true` for a note that is for the company's own\nstaff only.\n",
                "x-required-ability": "notes:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/NoteCreate"
                            },
                            "example": {
                                "body": "Gate code is 4471. Dog is friendly.",
                                "is_private": true
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new note.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Note"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/jobs/{id}/notes": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "get": {
                "tags": [
                    "Notes"
                ],
                "operationId": "listJobNotes",
                "summary": "List a job's notes",
                "description": "The notes written on the job, newest first.",
                "x-required-ability": "notes:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of notes, newest first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Note"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "tags": [
                    "Notes"
                ],
                "operationId": "createJobNote",
                "summary": "Add a note to a job",
                "description": "The note is added to the log under the name of the person who\ncreated the API key. A note cannot be edited or removed through the\nAPI.\n\nA note on a job is always internal to the company, whatever\n`is_private` says. It does not change the job's `notes` field.\n",
                "x-required-ability": "notes:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/NoteCreate"
                            },
                            "example": {
                                "body": "Customer asked for a call 30 minutes ahead."
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new note.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Note"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/jobs/{id}/photos": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "get": {
                "tags": [
                    "Photos and documents"
                ],
                "operationId": "listJobPhotos",
                "summary": "List a job's photos",
                "description": "The photos filed on a job.\nEach `url` works until `url_expires_at`, usually an hour after the\nrequest. Download the file or ask again for a fresh link; do not\nstore the link.\n",
                "x-required-ability": "photos:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "stage",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "before",
                                "during",
                                "after"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of photos, newest first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Photo"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/customers/{id}/photos": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "get": {
                "tags": [
                    "Photos and documents"
                ],
                "operationId": "listCustomerPhotos",
                "summary": "List a customer's photos",
                "description": "The photos filed on the customer. Photos filed on the customer's\njobs are listed under each job.\nEach `url` works until `url_expires_at`, usually an hour after the\nrequest. Download the file or ask again for a fresh link; do not\nstore the link.\n",
                "x-required-ability": "photos:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "stage",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "before",
                                "during",
                                "after"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of photos, newest first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Photo"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/customers/{id}/documents": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "get": {
                "tags": [
                    "Photos and documents"
                ],
                "operationId": "listCustomerDocuments",
                "summary": "List a customer's documents",
                "description": "The PDF documents filed on the customer.\nEach `url` works until `url_expires_at`, usually an hour after the\nrequest. Download the file or ask again for a fresh link; do not\nstore the link.\n",
                "x-required-ability": "photos:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of documents, newest first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Document"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/equipment": {
            "get": {
                "tags": [
                    "Equipment"
                ],
                "operationId": "listEquipment",
                "summary": "List equipment",
                "description": "Equipment recorded at customers' addresses, newest first. Filter by `customer_id` and `address_id` for one location.",
                "x-required-ability": "equipment:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "customer_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "address_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "enum": [
                                "furnace",
                                "ac",
                                "water_heater",
                                "other"
                            ]
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of equipment, newest first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Equipment"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/equipment/{id}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "get": {
                "tags": [
                    "Equipment"
                ],
                "operationId": "getEquipment",
                "summary": "Get a piece of equipment",
                "x-required-ability": "equipment:read",
                "responses": {
                    "200": {
                        "description": "The equipment.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Equipment"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/availability": {
            "get": {
                "tags": [
                    "Booking"
                ],
                "operationId": "listAvailability",
                "summary": "List open time slots",
                "description": "The times a visit can be booked for a location, soonest day first.\nThese are the slots the company's own online booking page would\noffer: inside business hours, with a technician free, starting\ntomorrow. Times are in the company's timezone, given in `timezone`.\n\nA `job_type_id` that is not one of the company's is a `404`. One the\ncompany has not opened for booking is a `422`.\n\nWhen the location is outside the company's service area,\n`in_service_area` is `false` and `data` is empty. Not paginated: use\n`limit`.\n",
                "x-required-ability": "availability:read",
                "parameters": [
                    {
                        "name": "zip",
                        "in": "query",
                        "required": true,
                        "description": "ZIP code of the place to be visited.",
                        "schema": {
                            "type": "string",
                            "maxLength": 16
                        }
                    },
                    {
                        "name": "address",
                        "in": "query",
                        "description": "Street address. Lets Couplr favor times when a technician is already nearby.",
                        "schema": {
                            "type": "string",
                            "maxLength": 255
                        }
                    },
                    {
                        "name": "job_type_id",
                        "in": "query",
                        "description": "A job type the company has opened for booking. Slots are sized to its usual length.",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "description": "How many slots to return. Default 24, at most 100.",
                        "schema": {
                            "type": "integer",
                            "minimum": 1,
                            "default": 24
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Open slots, soonest day first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "in_service_area",
                                        "timezone"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/TimeSlot"
                                            }
                                        },
                                        "in_service_area": {
                                            "type": "boolean"
                                        },
                                        "timezone": {
                                            "type": "string",
                                            "description": "IANA timezone the dates and times are in, e.g. `America/Chicago`."
                                        }
                                    }
                                },
                                "example": {
                                    "data": [
                                        {
                                            "date": "2026-11-16",
                                            "time": "09:00",
                                            "arrival_window_end": "11:00"
                                        },
                                        {
                                            "date": "2026-11-16",
                                            "time": "13:00",
                                            "arrival_window_end": "15:00"
                                        }
                                    ],
                                    "in_service_area": true,
                                    "timezone": "America/Chicago"
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/bookings": {
            "post": {
                "tags": [
                    "Booking"
                ],
                "operationId": "createBooking",
                "summary": "Book a visit",
                "description": "Books a visit for an existing customer into an open slot. Send a\n`date` and `time` from `GET /availability`. The visit is created as a\njob at the customer's address and given to a technician.\n\nWhat happens next depends on the job type, as it does when a\ncustomer books online:\n\n- A job type the company books automatically is `confirmed`. The\n  `booking.created` event is delivered, and the customer receives\n  the company's booking confirmation text if the company has that\n  text switched on.\n- Any other job type, or none, is `needs_review`: it is on the\n  schedule as tentative and the office is alerted to confirm the\n  time. The customer receives the company's appointment text if the\n  company has that text switched on, as for any new job.\n\nRefused with `422` when the slot is no longer open (on `time`), the\ncustomer has no address with a street and ZIP code or the address is\noutside the service area (on `address_id`), or the job type is not\nopen for booking (on `job_type_id`).\n",
                "x-required-ability": "bookings:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/BookingCreate"
                            },
                            "example": {
                                "customer_id": 1842,
                                "job_type_id": 31,
                                "date": "2026-11-16",
                                "time": "09:00",
                                "notes": "No cooling upstairs."
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The booking.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Booking"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/maintenance-plans": {
            "get": {
                "tags": [
                    "Maintenance plans"
                ],
                "operationId": "listMaintenancePlans",
                "summary": "List maintenance plans",
                "description": "The plans the company sells, in name order. A plan counts as changed for `updated_since` when one of its prices changes.",
                "x-required-ability": "plans:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of maintenance plans, in name order.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/MaintenancePlan"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/maintenance-plans/{id}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "get": {
                "tags": [
                    "Maintenance plans"
                ],
                "operationId": "getMaintenancePlan",
                "summary": "Get a maintenance plan",
                "x-required-ability": "plans:read",
                "responses": {
                    "200": {
                        "description": "The plan.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/MaintenancePlan"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/maintenance-plan-enrollments": {
            "get": {
                "tags": [
                    "Maintenance plans"
                ],
                "operationId": "listMaintenancePlanEnrollments",
                "summary": "List plan enrollments",
                "description": "Each customer's enrollment in a plan, newest first.",
                "x-required-ability": "plans:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "customer_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "plan_id",
                        "in": "query",
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "description": "Exact status match, e.g. `active`.",
                        "schema": {
                            "type": "string",
                            "maxLength": 50
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of enrollments, newest first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/MaintenancePlanEnrollment"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "tags": [
                    "Maintenance plans"
                ],
                "operationId": "createMaintenancePlanEnrollment",
                "summary": "Enroll a customer in a plan",
                "description": "Starts an enrollment. It is created with status `pending payment`\nand a `checkout_url`: Couplr's checkout page for this customer and\nplan. **Nothing is charged by this call.** Billing starts when the\ncustomer completes the checkout page, and the enrollment then\nbecomes `active`.\n\nCouplr also books the plan's first visit on the schedule and, if the\ncustomer uses email, sends them the plan email with the checkout\nlink, as it does when someone enrolls a customer in the apps.\n\n`billing_frequency` must be one of the plan's current `prices`. The\nprice is the plan's own; it cannot be set here, and neither can a\ndiscount.\n\nA repeat of the same enrollment within a few minutes returns the\nfirst one with `200` instead of creating a second.\n\nRefused with `422` when the account has no checkout page for the\ncustomer to complete (on `plan_id`); enroll the customer in Couplr\ninstead. If the checkout page cannot be created at that moment, the\nanswer is also a `422`: the enrollment is kept as `pending payment`\nin Couplr for the office to send, and is never made active. An enrollment cannot be changed or cancelled through the API.\n",
                "x-required-ability": "plans:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/MaintenancePlanEnrollmentCreate"
                            },
                            "example": {
                                "customer_id": 1842,
                                "plan_id": 12,
                                "billing_frequency": "month"
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The same enrollment was made moments ago. That enrollment is returned.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/MaintenancePlanEnrollment"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "201": {
                        "description": "The new enrollment, pending payment.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/MaintenancePlanEnrollment"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/maintenance-plan-enrollments/{id}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "get": {
                "tags": [
                    "Maintenance plans"
                ],
                "operationId": "getMaintenancePlanEnrollment",
                "summary": "Get a plan enrollment",
                "x-required-ability": "plans:read",
                "responses": {
                    "200": {
                        "description": "The enrollment.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/MaintenancePlanEnrollment"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/leads": {
            "get": {
                "tags": [
                    "Leads"
                ],
                "operationId": "listLeads",
                "summary": "List leads",
                "x-required-ability": "leads:read",
                "parameters": [
                    {
                        "$ref": "#/components/parameters/Page"
                    },
                    {
                        "$ref": "#/components/parameters/PerPage"
                    },
                    {
                        "$ref": "#/components/parameters/UpdatedSince"
                    },
                    {
                        "name": "channel",
                        "in": "query",
                        "description": "Exact match, e.g. `sms`, `web_chat`, `voice`.",
                        "schema": {
                            "type": "string",
                            "maxLength": 50
                        }
                    },
                    {
                        "name": "status",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "maxLength": 50
                        }
                    },
                    {
                        "name": "created_from",
                        "in": "query",
                        "schema": {
                            "type": "string",
                            "format": "date"
                        }
                    }
                ],
                "responses": {
                    "200": {
                        "description": "A page of leads, newest first.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "meta"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/Lead"
                                            }
                                        },
                                        "meta": {
                                            "$ref": "#/components/schemas/PageMeta"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "tags": [
                    "Leads"
                ],
                "operationId": "createLead",
                "summary": "Create a lead",
                "description": "Adds a lead. The person is matched to an existing customer by phone\nnumber, or added as a new customer, and the lead appears in Speed to\nLead with a note for the office to follow up by phone.\n\n**By default nobody is texted.** To have Couplr's assistant open a\ntext conversation with the person, send both\n`\"start_conversation\": true` and `\"sms_consent\": true`. Send\n`sms_consent` only when the person has agreed to receive texts from\nthis company. A conversation that ends with the assistant booking a\nvisit counts as one booked lead on the account's plan, the same as a\nlead from the website form.\n\nEven when asked, no text is sent if texting is not set up for the\naccount, the person has replied STOP before, or the number is not a\nUS or Canadian one. The lead is still created, and the response says\nwhy in `conversation_not_started_reason`.\n\nEach call creates a lead. Send an `Idempotency-Key` so a retry does\nnot create a second one.\n",
                "x-required-ability": "leads:write",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/LeadCreate"
                            },
                            "example": {
                                "name": "Dana Whitfield",
                                "phone": "555-201-8890",
                                "zip": "74105"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The new lead, and whether a text conversation was started.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data",
                                        "conversation_started",
                                        "conversation_not_started_reason"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Lead"
                                        },
                                        "conversation_started": {
                                            "type": "boolean",
                                            "description": "True when the intro text was sent."
                                        },
                                        "conversation_not_started_reason": {
                                            "type": "string",
                                            "nullable": true,
                                            "description": "Why no text was sent although `start_conversation` was true. Null otherwise."
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/leads/{id}": {
            "parameters": [
                {
                    "name": "id",
                    "in": "path",
                    "required": true,
                    "schema": {
                        "type": "string",
                        "format": "uuid"
                    }
                }
            ],
            "get": {
                "tags": [
                    "Leads"
                ],
                "operationId": "getLead",
                "summary": "Get a lead",
                "x-required-ability": "leads:read",
                "responses": {
                    "200": {
                        "description": "The lead.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/Lead"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/webhook-subscriptions": {
            "get": {
                "tags": [
                    "Webhook subscriptions"
                ],
                "operationId": "listWebhookSubscriptions",
                "summary": "List webhook subscriptions",
                "description": "Every outbound webhook destination of the company, including ones added on the Integrations page. Not paginated.",
                "x-required-ability": "webhooks:manage",
                "responses": {
                    "200": {
                        "description": "The whole list.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "type": "array",
                                            "items": {
                                                "$ref": "#/components/schemas/WebhookSubscription"
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "post": {
                "tags": [
                    "Webhook subscriptions"
                ],
                "operationId": "createWebhookSubscription",
                "summary": "Create a webhook subscription",
                "description": "Couplr will `POST` each chosen event to the URL. The response includes\nthe signing `secret`, which is shown only this once: store it and use\nit to verify `X-Hvacpro-Signature` on every delivery.\n\nThe subscription is tied to the API key that created it. Revoking that\nkey turns the subscription off (`active: false`, `disabled_reason:\n\"Creating API key revoked\"`), and while the key is expired nothing is\ndelivered.\n",
                "x-required-ability": "webhooks:manage",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/WebhookSubscriptionCreate"
                            },
                            "example": {
                                "url": "https://example.com/couplr-events",
                                "events": [
                                    "invoice.paid",
                                    "job.completed"
                                ],
                                "description": "Accounting sync"
                            }
                        }
                    }
                },
                "responses": {
                    "201": {
                        "description": "The subscription, with its signing secret.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "allOf": [
                                                {
                                                    "$ref": "#/components/schemas/WebhookSubscription"
                                                },
                                                {
                                                    "type": "object",
                                                    "required": [
                                                        "secret"
                                                    ],
                                                    "properties": {
                                                        "secret": {
                                                            "type": "string",
                                                            "description": "Signing secret. Returned only when the subscription is created."
                                                        }
                                                    }
                                                }
                                            ]
                                        }
                                    }
                                },
                                "example": {
                                    "data": {
                                        "id": 14,
                                        "url": "https://example.com/couplr-events",
                                        "description": "Accounting sync",
                                        "events": [
                                            "invoice.paid",
                                            "job.completed"
                                        ],
                                        "active": true,
                                        "disabled_reason": null,
                                        "last_delivery_at": null,
                                        "created_at": "2026-11-14T15:10:00+00:00",
                                        "secret": "YOUR_SIGNING_SECRET"
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        },
        "/webhook-subscriptions/{id}": {
            "parameters": [
                {
                    "$ref": "#/components/parameters/IntegerId"
                }
            ],
            "patch": {
                "tags": [
                    "Webhook subscriptions"
                ],
                "operationId": "updateWebhookSubscription",
                "summary": "Update a webhook subscription",
                "description": "Change the URL, the events or the description, or turn it off and on. Turning one back on clears its failure count.",
                "x-required-ability": "webhooks:manage",
                "x-idempotent": true,
                "parameters": [
                    {
                        "$ref": "#/components/parameters/IdempotencyKey"
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/WebhookSubscriptionUpdate"
                            },
                            "example": {
                                "active": false
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "The updated subscription.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "required": [
                                        "data"
                                    ],
                                    "properties": {
                                        "data": {
                                            "$ref": "#/components/schemas/WebhookSubscription"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "422": {
                        "$ref": "#/components/responses/ValidationFailed"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            },
            "delete": {
                "tags": [
                    "Webhook subscriptions"
                ],
                "operationId": "deleteWebhookSubscription",
                "summary": "Delete a webhook subscription",
                "description": "Stops deliveries and removes the subscription and its delivery history.",
                "x-required-ability": "webhooks:manage",
                "responses": {
                    "204": {
                        "description": "Deleted. No body."
                    },
                    "401": {
                        "$ref": "#/components/responses/Unauthorized"
                    },
                    "403": {
                        "$ref": "#/components/responses/Forbidden"
                    },
                    "404": {
                        "$ref": "#/components/responses/NotFound"
                    },
                    "429": {
                        "$ref": "#/components/responses/RateLimited"
                    }
                }
            }
        }
    },
    "components": {
        "securitySchemes": {
            "apiKey": {
                "type": "http",
                "scheme": "bearer",
                "description": "A company API key (`hvp_\u2026`). Also accepted in `X-Api-Key`."
            }
        },
        "parameters": {
            "Page": {
                "name": "page",
                "in": "query",
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "default": 1
                }
            },
            "PerPage": {
                "name": "per_page",
                "in": "query",
                "description": "Values above 100 are served as 100.",
                "schema": {
                    "type": "integer",
                    "minimum": 1,
                    "default": 25
                }
            },
            "UpdatedSince": {
                "name": "updated_since",
                "in": "query",
                "description": "Only records changed at or after this time. ISO 8601, for example `2026-11-14T15:00:00Z`.",
                "schema": {
                    "type": "string",
                    "format": "date-time"
                }
            },
            "IntegerId": {
                "name": "id",
                "in": "path",
                "required": true,
                "schema": {
                    "type": "integer"
                }
            },
            "IdempotencyKey": {
                "name": "Idempotency-Key",
                "in": "header",
                "description": "Makes a retry of this request safe. See \"Retries and idempotency\".",
                "schema": {
                    "type": "string",
                    "maxLength": 100
                }
            }
        },
        "headers": {
            "RequestId": {
                "description": "Unique id for this request. Give it to support.",
                "schema": {
                    "type": "string",
                    "format": "uuid"
                }
            },
            "RetryAfter": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                    "type": "integer"
                }
            }
        },
        "responses": {
            "Unauthorized": {
                "description": "No key (`api_key_missing`), the key is unknown or revoked (`api_key_invalid`), the key had an end date that has passed (`api_key_expired`), or the key belongs to a private trial sandbox whose access window has ended (`sandbox_expired`).",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "about:blank",
                            "title": "Unauthorized",
                            "status": 401,
                            "detail": "Invalid or revoked API key.",
                            "code": "api_key_invalid",
                            "request_id": "6f1c1f0e-5b1d-4c35-9a59-2f1a0b7c9c11",
                            "message": "Invalid or revoked API key."
                        }
                    }
                }
            },
            "Forbidden": {
                "description": "The key lacks the ability this endpoint needs (`ability_missing`), no\nadmin user is left to act for the key (`no_acting_admin`), or the\ncompany's account is not yet verified.\n",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        }
                    }
                }
            },
            "NotFound": {
                "description": "No such record in this company (`not_found`).",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        }
                    }
                }
            },
            "ValidationFailed": {
                "description": "A parameter or field is invalid (`validation_failed`). `errors` maps each field to its messages.",
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        },
                        "example": {
                            "type": "about:blank",
                            "title": "Unprocessable Content",
                            "status": 422,
                            "detail": "The name field is required.",
                            "code": "validation_failed",
                            "request_id": "6f1c1f0e-5b1d-4c35-9a59-2f1a0b7c9c11",
                            "message": "The name field is required.",
                            "errors": {
                                "name": [
                                    "The name field is required."
                                ]
                            }
                        }
                    }
                }
            },
            "RateLimited": {
                "description": "Too many requests (`rate_limited`). Wait `Retry-After` seconds.",
                "headers": {
                    "Retry-After": {
                        "$ref": "#/components/headers/RetryAfter"
                    }
                },
                "content": {
                    "application/json": {
                        "schema": {
                            "$ref": "#/components/schemas/Problem"
                        }
                    }
                }
            }
        },
        "schemas": {
            "Ability": {
                "type": "string",
                "enum": [
                    "customers:read",
                    "customers:write",
                    "jobs:read",
                    "jobs:write",
                    "jobs:complete",
                    "invoices:read",
                    "invoices:write",
                    "invoices:send",
                    "payments:read",
                    "price-book:read",
                    "price-book:write",
                    "estimates:read",
                    "estimates:write",
                    "timesheets:read",
                    "notes:read",
                    "notes:write",
                    "photos:read",
                    "equipment:read",
                    "availability:read",
                    "bookings:write",
                    "plans:read",
                    "plans:write",
                    "leads:read",
                    "leads:write",
                    "webhooks:manage"
                ]
            },
            "Problem": {
                "type": "object",
                "description": "RFC 9457 problem details, plus `code`, `request_id`, and the older `message` / `errors` members.",
                "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "code",
                    "request_id",
                    "message"
                ],
                "properties": {
                    "type": {
                        "type": "string",
                        "description": "Always `about:blank`; branch on `code`."
                    },
                    "title": {
                        "type": "string"
                    },
                    "status": {
                        "type": "integer"
                    },
                    "detail": {
                        "type": "string"
                    },
                    "code": {
                        "type": "string",
                        "description": "Stable, machine-readable. New codes may be added.",
                        "example": "validation_failed"
                    },
                    "request_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "message": {
                        "type": "string",
                        "description": "Same text as `detail`."
                    },
                    "errors": {
                        "type": "object",
                        "description": "On `422` only. Field name to list of messages.",
                        "additionalProperties": {
                            "type": "array",
                            "items": {
                                "type": "string"
                            }
                        }
                    }
                },
                "additionalProperties": true
            },
            "PageMeta": {
                "type": "object",
                "required": [
                    "page",
                    "per_page",
                    "total",
                    "last_page"
                ],
                "properties": {
                    "page": {
                        "type": "integer"
                    },
                    "per_page": {
                        "type": "integer"
                    },
                    "total": {
                        "type": "integer"
                    },
                    "last_page": {
                        "type": "integer"
                    }
                }
            },
            "NamedItem": {
                "type": "object",
                "required": [
                    "id",
                    "name"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "Address": {
                "type": "object",
                "required": [
                    "id",
                    "address",
                    "city",
                    "state",
                    "zip_code"
                ],
                "example": {
                    "id": 2211,
                    "address": "88 Rental Row",
                    "city": "Tulsa",
                    "state": "OK",
                    "zip_code": "74104"
                },
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "address": {
                        "type": "string",
                        "nullable": true
                    },
                    "city": {
                        "type": "string",
                        "nullable": true
                    },
                    "state": {
                        "type": "string",
                        "nullable": true
                    },
                    "zip_code": {
                        "type": "string",
                        "nullable": true
                    }
                }
            },
            "AddressCreate": {
                "type": "object",
                "description": "Fields not listed are ignored.",
                "required": [
                    "address"
                ],
                "properties": {
                    "address": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "Street address."
                    },
                    "city": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255
                    },
                    "state": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255
                    },
                    "zip_code": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255
                    }
                }
            },
            "WebhookEvent": {
                "type": "string",
                "enum": [
                    "customer.created",
                    "job.created",
                    "job.completed",
                    "estimate.completed",
                    "invoice.sent",
                    "invoice.paid",
                    "invoice.refunded",
                    "estimate.accepted",
                    "lead.created",
                    "booking.created"
                ]
            },
            "WebhookSubscription": {
                "type": "object",
                "required": [
                    "id",
                    "url",
                    "description",
                    "events",
                    "active",
                    "disabled_reason",
                    "last_delivery_at",
                    "created_at"
                ],
                "example": {
                    "id": 14,
                    "url": "https://example.com/couplr-events",
                    "description": "Accounting sync",
                    "events": [
                        "invoice.paid",
                        "job.completed"
                    ],
                    "active": true,
                    "disabled_reason": null,
                    "last_delivery_at": null,
                    "created_at": "2026-11-14T15:10:00+00:00"
                },
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "url": {
                        "type": "string"
                    },
                    "description": {
                        "type": "string",
                        "nullable": true
                    },
                    "events": {
                        "type": "array",
                        "description": "Event names, or `*` for every event.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "active": {
                        "type": "boolean",
                        "description": "`false` when turned off, or turned off automatically after repeated failed deliveries."
                    },
                    "disabled_reason": {
                        "type": "string",
                        "nullable": true
                    },
                    "last_delivery_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "WebhookSubscriptionUpdate": {
                "type": "object",
                "description": "Fields not listed are ignored.",
                "properties": {
                    "url": {
                        "type": "string",
                        "maxLength": 2000,
                        "description": "Must start with `https://` and use a public hostname."
                    },
                    "description": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255
                    },
                    "events": {
                        "type": "array",
                        "minItems": 1,
                        "description": "Event names from the outbound webhook event list, or `*` for every event.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "active": {
                        "type": "boolean"
                    }
                }
            },
            "WebhookSubscriptionCreate": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/WebhookSubscriptionUpdate"
                    },
                    {
                        "type": "object",
                        "required": [
                            "url",
                            "events"
                        ]
                    }
                ]
            },
            "Customer": {
                "type": "object",
                "example": {
                    "id": 1842,
                    "name": "Dana Whitfield",
                    "email": "dana@example.com",
                    "phone": "5552018890",
                    "phone_is_mobile": true,
                    "addresses": [
                        {
                            "id": 2210,
                            "address": "412 Larkspur Ln",
                            "city": "Tulsa",
                            "state": "OK",
                            "zip_code": "74105"
                        }
                    ],
                    "created_at": "2026-11-14T15:02:11+00:00",
                    "updated_at": "2026-11-14T15:02:11+00:00"
                },
                "required": [
                    "id",
                    "name",
                    "email",
                    "phone",
                    "phone_is_mobile",
                    "addresses",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "email": {
                        "type": "string",
                        "nullable": true
                    },
                    "phone": {
                        "type": "string",
                        "nullable": true,
                        "description": "Digits only."
                    },
                    "phone_is_mobile": {
                        "type": "boolean"
                    },
                    "addresses": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/Address"
                        }
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "CustomerUpdate": {
                "type": "object",
                "description": "Fields not listed are ignored.",
                "properties": {
                    "name": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "email": {
                        "type": "string",
                        "format": "email",
                        "nullable": true
                    },
                    "uses_email": {
                        "type": "boolean",
                        "description": "`false` records that the customer has no email."
                    },
                    "phone": {
                        "type": "string",
                        "maxLength": 255,
                        "description": "Any format; stored as digits."
                    },
                    "phone_is_mobile": {
                        "type": "boolean"
                    },
                    "address": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255,
                        "description": "Updates the customer's primary address."
                    },
                    "city": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255
                    },
                    "state": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255
                    },
                    "zip_code": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255
                    },
                    "sms_consent": {
                        "type": "boolean",
                        "description": "Send only when the customer has agreed to receive texts. `true` records consent only when none is on file, and never clears an opt-out the customer made by texting STOP; only the customer can undo that, by texting START. `false` opts the customer out."
                    }
                }
            },
            "CustomerCreate": {
                "allOf": [
                    {
                        "$ref": "#/components/schemas/CustomerUpdate"
                    },
                    {
                        "type": "object",
                        "required": [
                            "name",
                            "phone"
                        ],
                        "description": "`email` is required unless `uses_email` is `false`.",
                        "properties": {
                            "send_card_request": {
                                "type": "boolean",
                                "default": false,
                                "description": "`true` emails the customer a request to put a card on file."
                            },
                            "ignore_duplicates": {
                                "type": "boolean",
                                "default": true,
                                "description": "`false` returns `409` with candidates when the name or address matches an existing customer."
                            }
                        }
                    }
                ]
            },
            "Job": {
                "type": "object",
                "example": {
                    "id": 9312,
                    "customer_id": 1842,
                    "customer_name": "Dana Whitfield",
                    "job_type": "Repair",
                    "scheduled_date": "2026-12-02",
                    "scheduled_start_time": "09:00:00",
                    "time_window_start": null,
                    "time_window_end": null,
                    "duration_minutes": null,
                    "is_completed": false,
                    "completed_at": null,
                    "notes": "No cooling upstairs. Gate code 4410.",
                    "source": null,
                    "created_at": "2026-11-14T15:04:40+00:00",
                    "updated_at": "2026-11-14T15:04:40+00:00"
                },
                "required": [
                    "id",
                    "customer_id",
                    "customer_name",
                    "job_type",
                    "scheduled_date",
                    "scheduled_start_time",
                    "time_window_start",
                    "time_window_end",
                    "duration_minutes",
                    "is_completed",
                    "completed_at",
                    "notes",
                    "source",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "customer_id": {
                        "type": "integer"
                    },
                    "customer_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "job_type": {
                        "type": "string",
                        "nullable": true
                    },
                    "scheduled_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "scheduled_start_time": {
                        "type": "string",
                        "nullable": true,
                        "description": "Company-local time of day, `HH:MM:SS`."
                    },
                    "time_window_start": {
                        "type": "string",
                        "nullable": true,
                        "description": "Company-local time of day."
                    },
                    "time_window_end": {
                        "type": "string",
                        "nullable": true,
                        "description": "Company-local time of day."
                    },
                    "duration_minutes": {
                        "type": "integer",
                        "nullable": true
                    },
                    "is_completed": {
                        "type": "boolean"
                    },
                    "completed_at": {
                        "type": "string",
                        "nullable": true,
                        "description": "`YYYY-MM-DD HH:MM:SS` in UTC (not ISO 8601)."
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "source": {
                        "type": "string",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "JobCreate": {
                "type": "object",
                "description": "Fields not listed are ignored. Every id must belong to the key's company.",
                "required": [
                    "customer_id"
                ],
                "properties": {
                    "customer_id": {
                        "type": "integer"
                    },
                    "job_type_id": {
                        "type": "integer",
                        "description": "Required unless `job_type` is sent."
                    },
                    "job_type": {
                        "type": "string",
                        "description": "A job type name, matched case-insensitively. See `GET /job-types`."
                    },
                    "address_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Required when the customer has more than one address."
                    },
                    "scheduled_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "Omit to leave the job unscheduled."
                    },
                    "scheduled_start_time": {
                        "type": "string",
                        "nullable": true,
                        "description": "Company-local time, e.g. `09:00`."
                    },
                    "use_time_window": {
                        "type": "boolean",
                        "description": "`true` books an arrival window (`time_window_*`) instead of a start time."
                    },
                    "time_window_start": {
                        "type": "string",
                        "nullable": true
                    },
                    "time_window_end": {
                        "type": "string",
                        "nullable": true
                    },
                    "duration_minutes": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 15,
                        "maximum": 1440
                    },
                    "days": {
                        "type": "array",
                        "nullable": true,
                        "description": "A multi-day job, one entry per day, instead of `scheduled_date`.",
                        "items": {
                            "type": "object",
                            "required": [
                                "date"
                            ],
                            "properties": {
                                "date": {
                                    "type": "string",
                                    "format": "date"
                                },
                                "scheduled_start_time": {
                                    "type": "string",
                                    "nullable": true
                                },
                                "time_window_start": {
                                    "type": "string",
                                    "nullable": true
                                },
                                "time_window_end": {
                                    "type": "string",
                                    "nullable": true
                                },
                                "duration_minutes": {
                                    "type": "integer",
                                    "nullable": true,
                                    "minimum": 15,
                                    "maximum": 1440
                                }
                            }
                        }
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "job_summary": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 5000
                    },
                    "kind": {
                        "type": "string",
                        "enum": [
                            "service",
                            "estimate"
                        ],
                        "default": "service",
                        "description": "An `estimate` visit must be scheduled."
                    },
                    "estimate_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "The estimate an estimate visit is for."
                    },
                    "is_maintenance": {
                        "type": "boolean",
                        "description": "Links the job to the customer's active maintenance plan."
                    },
                    "market_segment_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "lead_source_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "branch_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "business_unit_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "assigned_tech_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "A single technician. Omit every technician field to auto-dispatch."
                    },
                    "assigned_tech_ids": {
                        "type": "array",
                        "nullable": true,
                        "items": {
                            "type": "integer"
                        }
                    },
                    "lead_tech_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "tag_ids": {
                        "type": "array",
                        "maxItems": 50,
                        "items": {
                            "type": "integer"
                        }
                    }
                }
            },
            "JobUpdate": {
                "type": "object",
                "description": "Fields not listed are ignored. Every id must belong to the key's company.",
                "properties": {
                    "job_type_id": {
                        "type": "integer"
                    },
                    "job_type": {
                        "type": "string",
                        "description": "A job type name, matched case-insensitively. See `GET /job-types`."
                    },
                    "address_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "One of the job's customer's addresses."
                    },
                    "scheduled_date": {
                        "type": "string",
                        "format": "date",
                        "description": "Moves a single-day job to this day."
                    },
                    "scheduled_start_time": {
                        "type": "string",
                        "nullable": true,
                        "description": "Company-local time, e.g. `13:00`."
                    },
                    "use_time_window": {
                        "type": "boolean",
                        "description": "`true` books an arrival window (`time_window_*`) instead of a start time."
                    },
                    "time_window_start": {
                        "type": "string",
                        "nullable": true
                    },
                    "time_window_end": {
                        "type": "string",
                        "nullable": true
                    },
                    "duration_minutes": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 15,
                        "maximum": 1440
                    },
                    "days": {
                        "type": "array",
                        "minItems": 1,
                        "description": "Replaces the job's days with this list, for a multi-day job.",
                        "items": {
                            "type": "object",
                            "required": [
                                "date"
                            ],
                            "properties": {
                                "date": {
                                    "type": "string",
                                    "format": "date"
                                },
                                "scheduled_start_time": {
                                    "type": "string",
                                    "nullable": true
                                },
                                "time_window_start": {
                                    "type": "string",
                                    "nullable": true
                                },
                                "time_window_end": {
                                    "type": "string",
                                    "nullable": true
                                },
                                "duration_minutes": {
                                    "type": "integer",
                                    "nullable": true,
                                    "minimum": 15,
                                    "maximum": 1440
                                }
                            }
                        }
                    },
                    "unschedule": {
                        "type": "boolean",
                        "description": "`true` takes the job off the calendar. Not allowed for estimate visits or completed jobs."
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "job_summary": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 5000
                    },
                    "market_segment_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "lead_source_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "branch_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "business_unit_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "assigned_tech_ids": {
                        "type": "array",
                        "description": "Replaces the crew. An empty list clears it. See `GET /technicians`.",
                        "items": {
                            "type": "integer"
                        }
                    },
                    "lead_tech_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Sent with `assigned_tech_ids`."
                    }
                }
            },
            "Invoice": {
                "type": "object",
                "example": {
                    "id": "9d3f6a52-0c1e-4c57-9d0a-3a0f8a4a7b21",
                    "invoice_number": "1047",
                    "customer_id": 1842,
                    "customer_name": "Dana Whitfield",
                    "job_id": 9312,
                    "status": "paid",
                    "amount": "389.00",
                    "notes": null,
                    "hosted_invoice_url": null,
                    "created_at": "2026-12-02T17:20:05+00:00",
                    "updated_at": "2026-12-02T18:01:44+00:00"
                },
                "required": [
                    "id",
                    "invoice_number",
                    "customer_id",
                    "customer_name",
                    "job_id",
                    "status",
                    "amount",
                    "notes",
                    "hosted_invoice_url",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "invoice_number": {
                        "type": "string",
                        "nullable": true
                    },
                    "customer_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "customer_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "job_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "status": {
                        "type": "string",
                        "nullable": true
                    },
                    "amount": {
                        "type": "string",
                        "nullable": true,
                        "description": "Decimal string in dollars, e.g. `\"125.00\"`."
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true
                    },
                    "hosted_invoice_url": {
                        "type": "string",
                        "nullable": true,
                        "description": "The customer-facing payment page. Treat as a secret link."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "line_items": {
                        "type": "array",
                        "description": "On a single invoice only, not in lists.",
                        "items": {
                            "type": "object",
                            "required": [
                                "name",
                                "quantity",
                                "rate"
                            ],
                            "properties": {
                                "name": {
                                    "type": "string",
                                    "nullable": true
                                },
                                "quantity": {
                                    "type": "number",
                                    "nullable": true
                                },
                                "rate": {
                                    "type": "string",
                                    "nullable": true,
                                    "description": "Decimal string in dollars."
                                }
                            }
                        }
                    }
                }
            },
            "Payment": {
                "type": "object",
                "description": "Money collected on an invoice. Amounts are what the customer paid.\nRefunds are made against the invoice as a whole, so the two refund\namounts are the invoice's and repeat on each of its payments.\n",
                "example": {
                    "id": 5581,
                    "invoice_id": "9d3f6a52-0c1e-4c57-9d0a-3a0f8a4a7b21",
                    "invoice_number": "1047",
                    "customer_id": 1842,
                    "amount": "389.00",
                    "method": "card",
                    "status": "paid",
                    "paid_at": "2026-12-02T18:01:44+00:00",
                    "invoice_refunded_amount": "0.00",
                    "invoice_refund_pending_amount": "0.00",
                    "created_at": "2026-12-02T18:01:44+00:00",
                    "updated_at": "2026-12-02T18:01:44+00:00"
                },
                "required": [
                    "id",
                    "invoice_id",
                    "invoice_number",
                    "customer_id",
                    "amount",
                    "method",
                    "status",
                    "paid_at",
                    "invoice_refunded_amount",
                    "invoice_refund_pending_amount",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "invoice_id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "invoice_number": {
                        "type": "string",
                        "nullable": true
                    },
                    "customer_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "amount": {
                        "type": "string",
                        "description": "Decimal string in dollars, e.g. `\"125.00\"`."
                    },
                    "method": {
                        "type": "string",
                        "enum": [
                            "card",
                            "bank",
                            "financing",
                            "cash",
                            "check",
                            "other"
                        ],
                        "description": "How it was paid. `bank` is a bank transfer. `other` is a payment the company recorded as made outside Couplr."
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "paid",
                            "partially_refunded",
                            "refunded"
                        ],
                        "description": "`refunded` when the invoice has been refunded in full, `partially_refunded` when part of it has."
                    },
                    "paid_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "invoice_refunded_amount": {
                        "type": "string",
                        "description": "Total refunded on the invoice so far. Decimal string in dollars."
                    },
                    "invoice_refund_pending_amount": {
                        "type": "string",
                        "description": "Refunds requested on the invoice and not yet completed. Decimal string in dollars."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "The later of the payment's and its invoice's last change."
                    }
                }
            },
            "JobComplete": {
                "type": "object",
                "description": "Fields not listed are ignored.",
                "properties": {
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 5000,
                        "description": "Added to the job's notes log."
                    }
                }
            },
            "PriceBookItem": {
                "type": "object",
                "example": {
                    "id": 771,
                    "name": "Condenser fan motor",
                    "description": "1/4 HP, 825 RPM, universal fit.",
                    "type": "material",
                    "unit_price": "289.00",
                    "part_number": "FM-2500",
                    "created_at": "2026-11-14T15:02:11+00:00",
                    "updated_at": "2026-11-14T15:02:11+00:00"
                },
                "required": [
                    "id",
                    "name",
                    "description",
                    "type",
                    "unit_price",
                    "part_number",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer",
                        "description": "Use as `price_book_item_id` on an invoice line."
                    },
                    "name": {
                        "type": "string"
                    },
                    "description": {
                        "type": "string",
                        "nullable": true,
                        "description": "The description customers see."
                    },
                    "type": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "equipment",
                            "labor",
                            "material",
                            "fee"
                        ],
                        "description": "The shelf the item is filed on."
                    },
                    "unit_price": {
                        "type": "string",
                        "nullable": true,
                        "description": "The price charged for one. Decimal string in dollars, e.g. `\"125.00\"`."
                    },
                    "part_number": {
                        "type": "string",
                        "nullable": true,
                        "description": "The manufacturer's part number."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "PriceBookItemCreate": {
                "type": "object",
                "description": "Fields not listed are ignored.",
                "required": [
                    "name",
                    "unit_price"
                ],
                "properties": {
                    "name": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "description": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000
                    },
                    "type": {
                        "type": "string",
                        "enum": [
                            "equipment",
                            "labor",
                            "material",
                            "fee"
                        ],
                        "default": "material"
                    },
                    "unit_price": {
                        "type": "number",
                        "minimum": 0,
                        "description": "The price charged for one, in dollars."
                    },
                    "part_number": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255
                    }
                }
            },
            "PriceBookItemUpdate": {
                "type": "object",
                "description": "Fields not listed are ignored.",
                "properties": {
                    "name": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "description": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000
                    },
                    "unit_price": {
                        "type": "number",
                        "minimum": 0
                    },
                    "part_number": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255
                    }
                }
            },
            "InvoiceDraftCreate": {
                "type": "object",
                "description": "Fields not listed are ignored. The invoice is always created as a draft.",
                "required": [
                    "customer_id",
                    "line_items"
                ],
                "properties": {
                    "customer_id": {
                        "type": "integer"
                    },
                    "job_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "A job of this customer to attach the invoice to."
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 5000
                    },
                    "due_days": {
                        "type": "integer",
                        "nullable": true,
                        "minimum": 0,
                        "maximum": 365,
                        "description": "Payment terms in days. Omit to use the company default."
                    },
                    "line_items": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "object",
                            "properties": {
                                "price_book_item_id": {
                                    "type": "integer",
                                    "nullable": true,
                                    "description": "An existing price book item. When sent, `name` is not needed."
                                },
                                "name": {
                                    "type": "string",
                                    "maxLength": 255,
                                    "description": "Required without `price_book_item_id`."
                                },
                                "description": {
                                    "type": "string",
                                    "nullable": true,
                                    "maxLength": 2000
                                },
                                "quantity": {
                                    "type": "number",
                                    "minimum": 0.001,
                                    "default": 1
                                },
                                "unit_price": {
                                    "type": "number",
                                    "minimum": 0,
                                    "description": "Dollars. Required without `price_book_item_id`. With one, defaults to the price book price."
                                }
                            }
                        }
                    }
                }
            },
            "Estimate": {
                "type": "object",
                "example": {
                    "id": 511,
                    "layout": "simple",
                    "title": "Replace condenser fan motor",
                    "customer_id": 1842,
                    "customer_name": "Dana Whitfield",
                    "status": "accepted",
                    "total": 389,
                    "accepted_at": "2026-12-01T16:45:00+00:00",
                    "declined_at": null,
                    "created_at": "2026-11-30T14:10:00+00:00",
                    "updated_at": "2026-12-01T16:45:00+00:00"
                },
                "required": [
                    "id",
                    "layout",
                    "title",
                    "customer_id",
                    "customer_name",
                    "status",
                    "total",
                    "accepted_at",
                    "declined_at",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "layout": {
                        "type": "string",
                        "enum": [
                            "simple",
                            "sectioned"
                        ],
                        "description": "`simple` is one list of items. `sectioned` groups the items under headings."
                    },
                    "title": {
                        "type": "string",
                        "nullable": true
                    },
                    "customer_id": {
                        "type": "integer"
                    },
                    "customer_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "draft",
                            "sent",
                            "accepted",
                            "declined"
                        ]
                    },
                    "total": {
                        "type": "number",
                        "nullable": true,
                        "description": "Dollars."
                    },
                    "accepted_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "declined_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "line_items": {
                        "type": "array",
                        "description": "On a single estimate with the `simple` layout only, not in lists.",
                        "items": {
                            "type": "object",
                            "required": [
                                "name",
                                "quantity",
                                "rate"
                            ],
                            "properties": {
                                "name": {
                                    "type": "string",
                                    "nullable": true
                                },
                                "quantity": {
                                    "type": "number",
                                    "nullable": true
                                },
                                "rate": {
                                    "type": "string",
                                    "nullable": true,
                                    "description": "Decimal string in dollars."
                                }
                            }
                        }
                    }
                }
            },
            "EstimateCreate": {
                "type": "object",
                "description": "Fields not listed are ignored. The estimate always has the `simple` layout.",
                "required": [
                    "customer_id",
                    "line_items"
                ],
                "properties": {
                    "customer_id": {
                        "type": "integer"
                    },
                    "title": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 255,
                        "description": "A name for the estimate. It is shown on the estimate in Couplr's lists and search."
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 5000
                    },
                    "send": {
                        "type": "boolean",
                        "default": false,
                        "description": "Email the estimate to the customer once it is ready. The customer must have an email address."
                    },
                    "line_items": {
                        "type": "array",
                        "minItems": 1,
                        "maxItems": 100,
                        "items": {
                            "type": "object",
                            "properties": {
                                "price_book_item_id": {
                                    "type": "integer",
                                    "nullable": true,
                                    "description": "An existing price book item. When sent, `name` is not used."
                                },
                                "name": {
                                    "type": "string",
                                    "nullable": true,
                                    "maxLength": 255,
                                    "description": "Required unless `price_book_item_id` is sent."
                                },
                                "quantity": {
                                    "type": "integer",
                                    "minimum": 1,
                                    "default": 1,
                                    "description": "A whole number."
                                },
                                "unit_price": {
                                    "type": "number",
                                    "nullable": true,
                                    "minimum": 0,
                                    "description": "Dollars. Required unless `price_book_item_id` is sent, when it defaults to the item's price."
                                }
                            }
                        }
                    }
                }
            },
            "TimeEntry": {
                "type": "object",
                "example": {
                    "id": 30211,
                    "technician_id": 14,
                    "technician_name": "Sam Wrench",
                    "job_id": 9312,
                    "type": "job",
                    "category": null,
                    "clock_in_at": "2026-11-14T15:02:11+00:00",
                    "clock_out_at": "2026-11-14T16:47:40+00:00",
                    "worked_minutes": 95,
                    "created_at": "2026-11-14T15:02:11+00:00",
                    "updated_at": "2026-11-14T16:47:40+00:00"
                },
                "required": [
                    "id",
                    "technician_id",
                    "technician_name",
                    "job_id",
                    "type",
                    "category",
                    "clock_in_at",
                    "clock_out_at",
                    "worked_minutes",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "technician_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "technician_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "job_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "Null for time that was not on a job."
                    },
                    "type": {
                        "type": "string",
                        "enum": [
                            "job",
                            "shift"
                        ],
                        "description": "`job` is time clocked on a job. `shift` is other paid time."
                    },
                    "category": {
                        "type": "string",
                        "nullable": true,
                        "description": "For `shift` time, what it was for, e.g. \"Shop\"."
                    },
                    "clock_in_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "clock_out_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true,
                        "description": "Null while the person is still clocked in."
                    },
                    "worked_minutes": {
                        "type": "integer",
                        "description": "Time on the clock less breaks. Still counting while `clock_out_at` is null."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "ScheduleEvent": {
                "type": "object",
                "example": {
                    "id": 512,
                    "kind": "time_off",
                    "title": "Vacation",
                    "date": "2026-12-24",
                    "start_time": null,
                    "end_time": null,
                    "is_company_wide": false,
                    "technician_ids": [
                        14
                    ],
                    "created_at": "2026-11-01T12:00:00+00:00",
                    "updated_at": "2026-11-01T12:00:00+00:00"
                },
                "required": [
                    "id",
                    "kind",
                    "title",
                    "date",
                    "start_time",
                    "end_time",
                    "is_company_wide",
                    "technician_ids",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "kind": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "time_off",
                            "meeting",
                            "hold",
                            "other"
                        ]
                    },
                    "title": {
                        "type": "string",
                        "nullable": true
                    },
                    "date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "start_time": {
                        "type": "string",
                        "nullable": true,
                        "description": "24-hour `HH:MM`. Null with `end_time` for an all-day event."
                    },
                    "end_time": {
                        "type": "string",
                        "nullable": true
                    },
                    "is_company_wide": {
                        "type": "boolean",
                        "description": "True when the event is for everyone."
                    },
                    "technician_ids": {
                        "type": "array",
                        "description": "The people the event is for. Empty when it is for everyone.",
                        "items": {
                            "type": "integer"
                        }
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "DeletedRecord": {
                "type": "object",
                "example": {
                    "type": "job",
                    "id": "9312",
                    "deleted_at": "2026-11-14T15:02:11+00:00"
                },
                "required": [
                    "type",
                    "id",
                    "deleted_at"
                ],
                "properties": {
                    "type": {
                        "type": "string",
                        "enum": [
                            "customer",
                            "job",
                            "invoice",
                            "estimate"
                        ]
                    },
                    "id": {
                        "type": "string",
                        "description": "The record's id, always as a string: `\"9312\"` for a job, a UUID for an invoice."
                    },
                    "deleted_at": {
                        "type": "string",
                        "format": "date-time"
                    }
                }
            },
            "Note": {
                "type": "object",
                "example": {
                    "id": 9021,
                    "body": "Gate code is 4471. Dog is friendly.",
                    "is_private": true,
                    "is_pinned": false,
                    "author_name": "Sam Whitfield",
                    "created_at": "2026-11-14T15:02:11+00:00",
                    "updated_at": "2026-11-14T15:02:11+00:00"
                },
                "required": [
                    "id",
                    "body",
                    "is_private",
                    "is_pinned",
                    "author_name",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "body": {
                        "type": "string"
                    },
                    "is_private": {
                        "type": "boolean",
                        "description": "For the company's own staff only. Notes on a job always are."
                    },
                    "is_pinned": {
                        "type": "boolean",
                        "description": "Shown at the top of the record in Couplr."
                    },
                    "author_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "NoteCreate": {
                "type": "object",
                "description": "Fields not listed are ignored.",
                "required": [
                    "body"
                ],
                "properties": {
                    "body": {
                        "type": "string",
                        "maxLength": 5000
                    },
                    "is_private": {
                        "type": "boolean",
                        "default": false,
                        "description": "For the company's own staff only. Ignored on a job, where every note is."
                    }
                }
            },
            "Photo": {
                "type": "object",
                "example": {
                    "id": 4410,
                    "caption": "Condenser before cleaning",
                    "description": null,
                    "stage": "before",
                    "taken_at": "2026-11-14T15:02:11+00:00",
                    "url": "https://files.example.com/photo-4410?signature=EXAMPLE",
                    "thumbnail_url": "https://files.example.com/photo-4410-thumb?signature=EXAMPLE",
                    "url_expires_at": "2026-11-14T17:10:00+00:00",
                    "created_at": "2026-11-14T15:03:00+00:00",
                    "updated_at": "2026-11-14T15:03:00+00:00"
                },
                "required": [
                    "id",
                    "caption",
                    "description",
                    "stage",
                    "taken_at",
                    "url",
                    "thumbnail_url",
                    "url_expires_at",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "caption": {
                        "type": "string",
                        "nullable": true
                    },
                    "description": {
                        "type": "string",
                        "nullable": true
                    },
                    "stage": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "before",
                            "during",
                            "after"
                        ]
                    },
                    "taken_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "url": {
                        "type": "string",
                        "nullable": true,
                        "description": "A link to the picture, with the company's markup when it has any. Works until `url_expires_at`."
                    },
                    "thumbnail_url": {
                        "type": "string",
                        "nullable": true,
                        "description": "A link to a small version. Works until `url_expires_at`."
                    },
                    "url_expires_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "Document": {
                "type": "object",
                "example": {
                    "id": 88,
                    "customer_id": 1842,
                    "file_name": "warranty-registration.pdf",
                    "size_bytes": 482113,
                    "url": "https://files.example.com/document-88?signature=EXAMPLE",
                    "url_expires_at": "2026-11-14T17:10:00+00:00",
                    "created_at": "2026-10-02T12:00:00+00:00",
                    "updated_at": "2026-10-02T12:00:00+00:00"
                },
                "required": [
                    "id",
                    "customer_id",
                    "file_name",
                    "size_bytes",
                    "url",
                    "url_expires_at",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "customer_id": {
                        "type": "integer"
                    },
                    "file_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "size_bytes": {
                        "type": "integer",
                        "nullable": true
                    },
                    "url": {
                        "type": "string",
                        "nullable": true,
                        "description": "A link to the PDF. Works until `url_expires_at`."
                    },
                    "url_expires_at": {
                        "type": "string",
                        "format": "date-time"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "Equipment": {
                "type": "object",
                "example": {
                    "id": 610,
                    "customer_id": 1842,
                    "address_id": 2210,
                    "type": "ac",
                    "name": "Upstairs unit",
                    "make": "TRANE",
                    "model": "4TTR4036L",
                    "serial": "21104XYZ3F",
                    "install_year": 2019,
                    "manufacture_year": 2018,
                    "created_at": "2026-05-02T16:00:00+00:00",
                    "updated_at": "2026-05-02T16:00:00+00:00"
                },
                "required": [
                    "id",
                    "customer_id",
                    "address_id",
                    "type",
                    "name",
                    "make",
                    "model",
                    "serial",
                    "install_year",
                    "manufacture_year",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "customer_id": {
                        "type": "integer"
                    },
                    "address_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "The address the equipment is installed at."
                    },
                    "type": {
                        "type": "string",
                        "nullable": true,
                        "enum": [
                            "furnace",
                            "ac",
                            "water_heater",
                            "other"
                        ]
                    },
                    "name": {
                        "type": "string",
                        "nullable": true,
                        "description": "What the company calls it, e.g. \"Upstairs unit\"."
                    },
                    "make": {
                        "type": "string",
                        "nullable": true
                    },
                    "model": {
                        "type": "string",
                        "nullable": true
                    },
                    "serial": {
                        "type": "string",
                        "nullable": true
                    },
                    "install_year": {
                        "type": "integer",
                        "nullable": true
                    },
                    "manufacture_year": {
                        "type": "integer",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "TimeSlot": {
                "type": "object",
                "example": {
                    "date": "2026-11-16",
                    "time": "09:00",
                    "arrival_window_end": "11:00"
                },
                "required": [
                    "date",
                    "time",
                    "arrival_window_end"
                ],
                "properties": {
                    "date": {
                        "type": "string",
                        "format": "date"
                    },
                    "time": {
                        "type": "string",
                        "description": "Start time, 24-hour `HH:MM`, in the company's timezone."
                    },
                    "arrival_window_end": {
                        "type": "string",
                        "nullable": true,
                        "description": "When the company promises an arrival window, the end of it (`HH:MM`). Otherwise null and `time` is the start time."
                    }
                }
            },
            "BookingCreate": {
                "type": "object",
                "description": "Fields not listed are ignored.",
                "required": [
                    "customer_id",
                    "date",
                    "time"
                ],
                "properties": {
                    "customer_id": {
                        "type": "integer"
                    },
                    "address_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "One of the customer's addresses. Omit to use their main address."
                    },
                    "job_type_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "A job type the company has opened for booking. Omit for a general visit."
                    },
                    "date": {
                        "type": "string",
                        "format": "date",
                        "description": "A date from `GET /availability`."
                    },
                    "time": {
                        "type": "string",
                        "description": "A time from `GET /availability`, 24-hour `HH:MM`."
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 2000
                    }
                }
            },
            "Booking": {
                "type": "object",
                "example": {
                    "job_id": 9312,
                    "customer_id": 1842,
                    "address_id": 2210,
                    "job_type": "Repair",
                    "status": "confirmed",
                    "date": "2026-11-16",
                    "time": "09:00",
                    "arrival_window_end": "11:00",
                    "timezone": "America/Chicago",
                    "created_at": "2026-11-14T15:02:11+00:00"
                },
                "required": [
                    "job_id",
                    "customer_id",
                    "address_id",
                    "job_type",
                    "status",
                    "date",
                    "time",
                    "arrival_window_end",
                    "timezone",
                    "created_at"
                ],
                "properties": {
                    "job_id": {
                        "type": "integer",
                        "description": "The job that was created. Read it through the Jobs endpoints."
                    },
                    "customer_id": {
                        "type": "integer"
                    },
                    "address_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "job_type": {
                        "type": "string",
                        "nullable": true
                    },
                    "status": {
                        "type": "string",
                        "enum": [
                            "confirmed",
                            "needs_review"
                        ],
                        "description": "`needs_review` means the office still has to confirm the time with the customer."
                    },
                    "date": {
                        "type": "string",
                        "format": "date"
                    },
                    "time": {
                        "type": "string"
                    },
                    "arrival_window_end": {
                        "type": "string",
                        "nullable": true
                    },
                    "timezone": {
                        "type": "string"
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "MaintenancePlan": {
                "type": "object",
                "description": "A maintenance plan the company sells.",
                "example": {
                    "id": 12,
                    "name": "Comfort Club",
                    "description": "Two tune-ups a year and priority scheduling.",
                    "visits_per_year": 2,
                    "prices": [
                        {
                            "billing_frequency": "month",
                            "price": "19.00"
                        },
                        {
                            "billing_frequency": "year",
                            "price": "199.00"
                        }
                    ],
                    "created_at": "2026-03-02T16:00:00+00:00",
                    "updated_at": "2026-03-02T16:00:00+00:00"
                },
                "required": [
                    "id",
                    "name",
                    "description",
                    "visits_per_year",
                    "prices",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "name": {
                        "type": "string"
                    },
                    "description": {
                        "type": "string",
                        "nullable": true
                    },
                    "visits_per_year": {
                        "type": "integer",
                        "description": "How many maintenance visits the plan includes each year."
                    },
                    "prices": {
                        "type": "array",
                        "description": "What a customer pays for one system, for each way the plan can be billed.",
                        "items": {
                            "type": "object",
                            "required": [
                                "billing_frequency",
                                "price"
                            ],
                            "properties": {
                                "billing_frequency": {
                                    "type": "string",
                                    "nullable": true,
                                    "description": "How often it is billed, e.g. `month` or `year`."
                                },
                                "price": {
                                    "type": "string",
                                    "description": "Decimal string in dollars."
                                }
                            }
                        }
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "MaintenancePlanEnrollment": {
                "type": "object",
                "description": "One customer's enrollment in a maintenance plan.",
                "example": {
                    "id": 340,
                    "plan_id": 12,
                    "plan_name": "Comfort Club",
                    "customer_id": 1842,
                    "customer_name": "Dana Whitfield",
                    "address_id": 2210,
                    "status": "active",
                    "start_date": "2026-03-15",
                    "number_of_systems": 1,
                    "billing_frequency": "month",
                    "recurring_amount": "19.00",
                    "next_billing_date": "2026-12-15",
                    "checkout_url": null,
                    "created_at": "2026-03-15T17:20:05+00:00",
                    "updated_at": "2026-11-15T09:00:00+00:00"
                },
                "required": [
                    "id",
                    "plan_id",
                    "plan_name",
                    "customer_id",
                    "customer_name",
                    "address_id",
                    "status",
                    "start_date",
                    "number_of_systems",
                    "billing_frequency",
                    "recurring_amount",
                    "next_billing_date",
                    "checkout_url",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "integer"
                    },
                    "plan_id": {
                        "type": "integer"
                    },
                    "plan_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "customer_id": {
                        "type": "integer"
                    },
                    "customer_name": {
                        "type": "string",
                        "nullable": true
                    },
                    "address_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "The service address the plan covers."
                    },
                    "status": {
                        "type": "string",
                        "nullable": true,
                        "description": "`active`, `pending payment`, or the status it ended in."
                    },
                    "start_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "number_of_systems": {
                        "type": "integer"
                    },
                    "billing_frequency": {
                        "type": "string",
                        "nullable": true
                    },
                    "recurring_amount": {
                        "type": "string",
                        "description": "What the customer is charged each billing period. Decimal string in dollars."
                    },
                    "next_billing_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true
                    },
                    "checkout_url": {
                        "type": "string",
                        "nullable": true,
                        "description": "While the status is `pending payment`, the page where the customer completes the enrollment. Treat as a secret link. Null otherwise."
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            },
            "MaintenancePlanEnrollmentCreate": {
                "type": "object",
                "description": "Fields not listed are ignored.",
                "required": [
                    "customer_id",
                    "plan_id",
                    "billing_frequency"
                ],
                "properties": {
                    "customer_id": {
                        "type": "integer"
                    },
                    "plan_id": {
                        "type": "integer"
                    },
                    "billing_frequency": {
                        "type": "string",
                        "description": "One of the plan's `prices`, e.g. `month` or `year`."
                    },
                    "address_id": {
                        "type": "integer",
                        "nullable": true,
                        "description": "The address the plan covers. Omit to use the customer's main address."
                    },
                    "start_date": {
                        "type": "string",
                        "format": "date",
                        "nullable": true,
                        "description": "Defaults to today."
                    },
                    "number_of_systems": {
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 50,
                        "default": 1
                    },
                    "notes": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 5000
                    }
                }
            },
            "LeadCreate": {
                "type": "object",
                "description": "Fields not listed are ignored.",
                "required": [
                    "name",
                    "phone"
                ],
                "properties": {
                    "name": {
                        "type": "string",
                        "maxLength": 255
                    },
                    "phone": {
                        "type": "string",
                        "maxLength": 32,
                        "description": "At least ten digits. Punctuation is ignored."
                    },
                    "zip": {
                        "type": "string",
                        "nullable": true,
                        "maxLength": 16,
                        "description": "Used to check the lead is inside the company's service area."
                    },
                    "start_conversation": {
                        "type": "boolean",
                        "default": false,
                        "description": "Have the assistant text this person to start a Speed to Lead conversation. Needs `sms_consent`."
                    },
                    "sms_consent": {
                        "type": "boolean",
                        "default": false,
                        "description": "True only when this person has agreed to receive texts from the company. Required when `start_conversation` is true."
                    }
                }
            },
            "Lead": {
                "type": "object",
                "example": {
                    "id": "01a1db67-3ef9-73f3-bf60-4e522919bef6",
                    "channel": "sms",
                    "status": "active",
                    "phone": "5552018890",
                    "zip": "74105",
                    "customer_id": 1842,
                    "collected": {
                        "issue": "No cooling upstairs"
                    },
                    "last_inbound_at": "2026-11-14T15:00:02+00:00",
                    "last_outbound_at": "2026-11-14T15:00:09+00:00",
                    "created_at": "2026-11-14T14:58:30+00:00",
                    "updated_at": "2026-11-14T15:00:09+00:00"
                },
                "required": [
                    "id",
                    "channel",
                    "status",
                    "phone",
                    "zip",
                    "customer_id",
                    "collected",
                    "last_inbound_at",
                    "last_outbound_at",
                    "created_at",
                    "updated_at"
                ],
                "properties": {
                    "id": {
                        "type": "string",
                        "format": "uuid"
                    },
                    "channel": {
                        "type": "string",
                        "nullable": true
                    },
                    "status": {
                        "type": "string",
                        "nullable": true
                    },
                    "phone": {
                        "type": "string",
                        "nullable": true
                    },
                    "zip": {
                        "type": "string",
                        "nullable": true
                    },
                    "customer_id": {
                        "type": "integer",
                        "nullable": true
                    },
                    "collected": {
                        "type": "object",
                        "nullable": true,
                        "description": "Whatever the assistant captured. Keys vary by lead.",
                        "additionalProperties": true
                    },
                    "last_inbound_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "last_outbound_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "created_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "updated_at": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    }
                }
            }
        }
    }
}