# Price book

> List, read, create and update the items a company puts on invoices and estimates.

- Canonical URL: https://couplrfsm.com/developers/api-reference/price-book
- Markdown: https://couplrfsm.com/developers/api-reference/price-book.md
- API version: v1 (base URL https://couplrfsm.com/api/v1)
- OpenAPI specification: https://couplrfsm.com/developers/openapi.yaml
- All documentation pages: https://couplrfsm.com/llms.txt

> **Flip:** The price book is the list of things a company sells: parts, equipment, labor and fees, each with a price. Use an item's id on an invoice line and I fill in the rest. I show what the customer sees, never what the item costs the company.

Base URL: `https://couplrfsm.com/api/v1`. Conventions shared by every endpoint (examples, ids, dates, money) are on the [API reference](https://couplrfsm.com/developers/api-reference) page. Errors, pagination and idempotency are in [Errors, limits and retries](https://couplrfsm.com/developers/errors-and-limits).

## List price book items

`GET /api/v1/price-book-items` · requires the `price-book:read` ability

The company's active items, in name order. Archived items and the lines Couplr adds itself, such as sales tax, are not listed.

**Query parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `page` | integer | No | Default: `1`. |
| `per_page` | integer | No | Values above 100 are served as 100. Default: `25`. |
| `updated_since` | string (date-time) | No | Only records changed at or after this time. ISO 8601, for example `2026-11-14T15:00:00Z`. |
| `search` | string | No | Matches part of the name or part number. |
| `type` | string: `equipment`, `labor`, `material`, `fee` | No |  |

**Example request**

```bash
curl "https://couplrfsm.com/api/v1/price-book-items" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Example response** (`200`)

```json
{
    "data": [
        {
            "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"
        }
    ],
    "meta": {
        "page": 1,
        "per_page": 25,
        "total": 1,
        "last_page": 1
    }
}
```

**Errors**

| Status | When |
| --- | --- |
| `401` | 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`). |
| `403` | The key lacks the ability this endpoint needs (`ability_missing`), no admin user is left to act for the key (`no_acting_admin`), or the company's account is not yet verified. |
| `422` | A parameter or field is invalid (`validation_failed`). `errors` maps each field to its messages. |
| `429` | Too many requests (`rate_limited`). Wait `Retry-After` seconds. |

## Create a price book item

`POST /api/v1/price-book-items` · requires the `price-book:write` ability · accepts `Idempotency-Key`

Adds an item to the price book. Names are not required to be unique,
so check the list first if you do not want two items with one name.

**Headers**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | string | No | Makes a retry of this request safe. See "Retries and idempotency". |

**Request body** (`application/json`)

Fields not listed are ignored.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | Yes |  |
| `description` | string or null | No |  |
| `type` | string: `equipment`, `labor`, `material`, `fee` | No | Default: `material`. |
| `unit_price` | number | Yes | The price charged for one, in dollars. |
| `part_number` | string or null | No |  |

**Example request**

```bash
curl -X POST "https://couplrfsm.com/api/v1/price-book-items" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: YOUR_UNIQUE_KEY" \
  -d '{"name":"Condenser fan motor","description":"1/4 HP, 825 RPM, universal fit.","type":"material","unit_price":289,"part_number":"FM-2500"}'
```

**Example response** (`201`)

```json
{
    "data": {
        "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"
    }
}
```

**Errors**

| Status | When |
| --- | --- |
| `401` | 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`). |
| `403` | The key lacks the ability this endpoint needs (`ability_missing`), no admin user is left to act for the key (`no_acting_admin`), or the company's account is not yet verified. |
| `422` | A parameter or field is invalid (`validation_failed`). `errors` maps each field to its messages. |
| `429` | Too many requests (`rate_limited`). Wait `Retry-After` seconds. |

## Get a price book item

`GET /api/v1/price-book-items/{id}` · requires the `price-book:read` ability

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | integer | Yes |  |

**Example request**

```bash
curl "https://couplrfsm.com/api/v1/price-book-items/1842" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

**Example response** (`200`)

```json
{
    "data": {
        "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"
    }
}
```

**Errors**

| Status | When |
| --- | --- |
| `401` | 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`). |
| `403` | The key lacks the ability this endpoint needs (`ability_missing`), no admin user is left to act for the key (`no_acting_admin`), or the company's account is not yet verified. |
| `404` | No such record in this company (`not_found`). |
| `429` | Too many requests (`rate_limited`). Wait `Retry-After` seconds. |

## Update a price book item

`PATCH /api/v1/price-book-items/{id}` · requires the `price-book:write` ability · accepts `Idempotency-Key`

Only the fields you send change. A new price applies to invoices and
estimates written from then on; ones already written keep the price
they were written with. An item's `type` cannot be changed here.

**Path parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | integer | Yes |  |

**Headers**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | string | No | Makes a retry of this request safe. See "Retries and idempotency". |

**Request body** (`application/json`)

Fields not listed are ignored.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | string | No |  |
| `description` | string or null | No |  |
| `unit_price` | number | No |  |
| `part_number` | string or null | No |  |

**Example request**

```bash
curl -X PATCH "https://couplrfsm.com/api/v1/price-book-items/1842" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: YOUR_UNIQUE_KEY" \
  -d '{"unit_price":305}'
```

**Example response** (`200`)

```json
{
    "data": {
        "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"
    }
}
```

**Errors**

| Status | When |
| --- | --- |
| `401` | 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`). |
| `403` | The key lacks the ability this endpoint needs (`ability_missing`), no admin user is left to act for the key (`no_acting_admin`), or the company's account is not yet verified. |
| `404` | No such record in this company (`not_found`). |
| `422` | A parameter or field is invalid (`validation_failed`). `errors` maps each field to its messages. |
| `429` | Too many requests (`rate_limited`). Wait `Retry-After` seconds. |
