# Finders

Use narrowed root endpoints before exact detail reads.

Canonical HTML: https://developer.shelfcycle.com/guides/finders

Use narrowed root endpoints to find typed resources before fetching exact detail, order context, or attached documents.

## Reference, search, finder, detail

v1.21 separates nine jobs:

| Job | Endpoint shape | Use it for |
| --- | --- | --- |
| Reference directory | `GET /reference/customers` | Active customer and supplier matching hints for local caches. This is not full profile detail. |
| Search | `GET /search?q=...` | Ambiguous, cross-resource resolution across customers, suppliers, contacts, products, sales orders, purchase orders, and locations. |
| Finder | `GET /customers?q=...` | Typed lookup when the workflow already knows the resource family and at least one narrowing predicate. |
| Detail | `GET /customers/{id}` | Hydrating one selected id after search or a finder returns the candidate. |
| Attached documents | `GET /products/{id}/documents` | Reading file links attached to one selected customer, supplier, or product parent. |
| Write readiness | `POST /notes?dryRun=true` | Checking a supported write before execution without mutating records. |
| Product setup references | `GET /product-families?q=...` | Resolving product family and packaging references before bounded product catalog writes. |
| Governed reports | `GET /reports` | Discovering and running allowed sales, purchasing, and open-order rollups. |
| Cost Book | `GET /cost-book-entries` | Reading current costs or exact product and supplier cost history. |

Root finder endpoints are not broad sync lists. They reject unfiltered requests, `updatedSince`, and status-only polling that would teach clients to export full ERP records.

Use the reference directory when a local tool needs active customer/supplier hints for matching. Use search or a finder when the workflow is resolving a specific target. Use detail and parent-scoped document endpoints only after selecting a visible record. Use reports for allowed aggregate rollups, not as substitutes for finders or detail reads.

## Company and product finders

| Endpoint | Scope | Narrow with |
| --- | --- | --- |
| `GET /customers` | `customers:read` | `q` or exact `externalId` |
| `GET /suppliers` | `suppliers:read` | `q` or exact `externalId` |
| `GET /products` | `products:read` | `q`, exact `code`, exact `externalId`, or `supplierId` |

Optional `limit` caps response size. `includeArchived` is explicit; archived records are never write targets.

## Active company reference directory

| Endpoint | Scope | Use it for |
| --- | --- | --- |
| `GET /reference/customers` | `company-reference:read` | Cursor-paged active customer matching hints. |
| `GET /reference/suppliers` | `company-reference:read` | Cursor-paged active supplier matching hints. |

Reference directory rows are active-only and sorted by `id_asc`. They can include display names, external ids, alternate names, website hosts, email domains, one phone, city, state, country, status, updatedAt, and URL. They do not include contacts, notes, order history, products, prices, costs, margin, payment terms, tax, ledger, raw street addresses, or arbitrary private metadata.

The directory accepts `limit`, `cursor`, and explicit `includeArchived=false`. It rejects archived export and incremental-refresh filters in v1.21.

```bash
curl "$SHELFCYCLE_API_BASE_URL/products?code=ACETONE-PAIL&limit=5" \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY"
```

Product payloads use supported catalog fields. `Product.name` is deprecated and is not exposed by the public API.

## Commercial document finders

| Endpoint | Scope | Narrow with |
| --- | --- | --- |
| `GET /orders` | `orders:read` | `orderNo`, `customerOrderNo`, `externalId`, `customerId`, an `orderedAtFrom`/`orderedAtTo` window, or a paired `updatedAtFrom`/`updatedAtTo` window. |
| `GET /purchase-orders` | `purchase-orders:read` | `orderNo`, `externalId`, `supplierId`, `linkedOrderId`, a `dueAtFrom`/`dueAtTo` window, or a paired `updatedAtFrom`/`updatedAtTo` window. |

`status` can refine an already narrowed order document finder, but it is not a standalone sync filter.

Use paired `updatedAtFrom` and `updatedAtTo` only for parent-row changed-record discovery on sales orders and purchase orders. The response includes each document `updatedAt`; when that mode is used, `meta.changedRecordBasis` reports `parent_updated_at`. It is not a cursor, webhook feed, child-line delta feed, or broad export.

## Detail reads

After selecting an id, hydrate the exact record:

```text
GET /customers/{id}
GET /suppliers/{id}
GET /products/{id}
GET /orders/{id}
GET /purchase-orders/{id}
GET /contacts/{id}
GET /notes/{id}
GET /customers/{id}/documents
GET /suppliers/{id}/documents
GET /products/{id}/documents
```

Detail and attached document DTOs are safe public shapes. They omit hidden app fields such as credit, margin, ledger, inventory, lots, binary file bodies, and accounting internals.

> **Guardrail**: If a finder returns `finder_filter_required` or `unsupported_sync_filter`, use the v1.21 repair fields to narrow the request. Do not add client-side loops that approximate a broad export.
