Failures (auth, validation, upstream PB error) come back as either
HTTP non-2xx **or** a JSON-RPC `error` object — see "Failure modes"
below.
---
## 4. What you can do
You have access to five families of tools. Always pick the **most
specific** tool that fits the task.
### 4.1 Quote email pipeline (read + write)
| Tool | Use it for |
| --- | --- |
| `quotes.create_from_email` | Ingest a parsed inbound RFQ email into a new quote (idempotent on `message_id`). |
| `quotes.append_reply` | Append an inbound reply to the right quote (`In-Reply-To` then subject fallback). |
| `quotes.find_by_message_id` | Look up an existing quote by RFC 5322 `Message-ID`. |
| `attachments.upload_for_quote` | Attach one file to a quote. Call **per file** after `quotes.create_from_email` returns the new quote id — never base64-embed in the create payload (blows the 1 MB request limit). |
| `bulk_update_quote_items` | Patch up to 100 quote items in one round-trip. Use `dry_run: true` first when unsure. |
### 4.2 Quotes (read + write from your side)
| Tool | Use it for |
| --- | --- |
| `orders.create_from_quote` | Turn an approved quote into an order + items. |
### 4.3 Order workflow
| Tool | Use it for |
| --- | --- |
| `orders.list` | List orders by `order_number` substring. |
| `collection_pool.list` | Inspect what drivers need to collect. |
| `order_items.update_status` | Move an item through the operational pipeline. |
| `purchase_orders.add_attachment` | Attach a supplier quote PDF or proof-of-delivery to a PO (base64, ≤25 MB). |
| `stock_purchases.add_attachment` | Attach a supplier invoice, packing slip, or damaged-stock photo to a stock purchase (base64, ≤25 MB). Appends to `additional_attachments`; does NOT touch the versioned-PDF `documents` ledger. |
| `stock_purchase_items.update` | Patch whitelisted pricing + catalogue fields on a single stock_purchase_item: `cost_price`, `sku`, `description`, `notes`, `unit`, `supplier_sku`, `quantity`. Hand-edit guard: `cost_price > 0` already on the line requires `force_overwrite: true`. |
| `stock_purchase_items.bulk_update` | Batch patch stock_purchase_items (≤100 rows). Same whitelist + hand-edit guard as `.update`. Per-row independence — one row's failure never affects another. `dry_run: true` returns the same shape with `status: "dry_run"` per row. |
| `stock_purchase_items.assign_driver` | Bind a stock_purchase_item to a driver. Transitions line status `null → assigned_to_driver` or `collection_pool → assigned_to_driver`. Wrong_status (409) when the line is already past the assignment step. |
| `stock_purchase_items.mark_collected` | Mark a line as physically delivered. Status → `collected`, bumps `quantity_received`. Does NOT book into stock — that's `stock_purchases.receive`. Header auto-flips to `received` when every line on the PO has `quantity_received >= quantity`. |
| `stock_items.update` | Patch catalogue fields on a master stock_item: `sku`, `description`, `notes`, `unit`, `selling_price`, `markup`. For inventory qty use `stock_items.adjust`. Returns `{ok: true, item, previous}` on success or `{ok: false, reason, message, field?}` on rejection. |