# 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.

## Choose the lookup for the job

Use the narrowest directory or lookup that matches the information already available:

| Job | Endpoint shape | Use it for |
| --- | --- | --- |
| Entity Resolution | `GET /entity-resolution?q=...&class=...` | Choosing one authorized customer, supplier, product, product family, sales order, purchase order, or salesperson ID from familiar wording. |
| Tags | `GET /tags` and `GET /tagged-records` | Browsing the organization tag vocabulary and finding authorized records carrying one exact tag. |
| Product Directory | `GET /product-directory` | Finding products and product families by UN/NA number, CAS number, hazard class, packing group, or name. |
| Reference directory | `GET /reference/customers` or `/reference/suppliers` | Active customer and supplier matching hints for local caches. This is not full profile detail. |
| Account setup references | `GET /representatives`, `/payment-terms`, or `/reference/ledger-accounts` | Resolving representatives, payment terms, and eligible supplier cost accounts before a profile write. |
| Search | `GET /search?q=...` | Existing broad discovery 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. |
| Reports | `GET /reports` | Discovering and running available sales, purchasing, open-order, pipeline, and customer receivables views. |
| Cost Book | `GET /cost-book-entries` | Reading current costs or exact product, supplier, and ship-from-location history. |

Company and product finders require a supported narrowing filter. Supported finders can narrow by who entered a record or when it was entered. Order finders also accept exact identifiers, status, related records, product criteria, business-date windows, or last-updated windows. Opportunity finders support focused filtering or authorized browsing with signed continuation.

Use Entity Resolution for new single-record binding. Use Tags or Product Directory when the source information is an exact tag or product identifier. Use the reference directory when a local tool needs active customer/supplier hints for matching, and use a typed finder when the resource family and narrowing filters are already known. Existing connections can continue using search for broad discovery. 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`, exact `externalId`, `pipelineStatus`, creator or created time, account ownership, setup details, or qualifying shipped-sales activity. |
| `GET /suppliers` | `suppliers:read` | `q`, exact `externalId`, creator, or created time. |
| `GET /products` | `products:read` | `q`, exact `code`, exact `externalId`, or `supplierId` |

Product creation filters are available through `GET /product-directory`, where they can be combined with the directory's product and product-family identity filters. Orders, purchase orders, opportunities, lots, Cost Book entries, Price Book entries, and certification records support the same `createdById`, `createdFrom`, and `createdTo` pattern. See [Created records](/guides/created-records) for the complete route list and examples.

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

### Customer ownership, setup, and shipped sales

The customer finder can narrow the current customer population with:

- `salesPersonId` for any active-location assignment.
- `salesOwnership=all`, `mine`, or `unassigned`. Unassigned means no owner on any active location.
- `setupIssues=missing_account_owner`, `missing_payment_terms`, `no_primary`, or `ambiguous_primary`. Multiple values use any-of matching.
- `salesActivity=any` or `none` together with both `salesFrom` and `salesTo` as inclusive organization-calendar dates.

Shipped-sales filtering also requires the acting person's current Sales Performance viewing access. Customer discovery without an activity filter remains available under its normal customer access.

```bash
curl "$SHELFCYCLE_API_BASE_URL/customers?salesOwnership=mine&setupIssues=missing_payment_terms&limit=25" \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY"

curl "$SHELFCYCLE_API_BASE_URL/customers?salesActivity=none&salesFrom=2026-01-01&salesTo=2026-09-08&limit=25" \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY"
```

Results include `owners` from every active location, primary account owner, payment terms, customer-service representative, `commercialTermsState`, location coverage, and the applied shipped-sales basis. Qualifying shipped sales use the dates and activity definition returned with the response.

If `meta.hasMore` is true, continue with `meta.nextCursor` alone. Customer pages are current-state reads, so deduplicate by customer ID and use the returned `updatedAt` values when reconciling later changes.

## Company reference directories

| 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. |
| `GET /representatives` | `company-reference:read` | Salesperson, customer-service, and supplier representatives by kind, name, or source ID. |
| `GET /payment-terms` | `company-reference:read` | Payment-term identities and their exact net and discount values. |
| `GET /reference/ledger-accounts` | `company-reference:read` | Eligible ledger-account metadata for supplier cost-account selection. |

Customer and supplier reference rows are active matching hints sorted by `id_asc`. They can include display names, source IDs, alternate names, website hosts, email domains, one phone, city, state, country, status, `updatedAt`, and URL.

Representative, payment-term, and ledger-account directories are sorted by name and ID. Representative identity always includes `kind`; payment terms return their exact financial definition; ledger accounts return account type and selection metadata without balances.

Directories accept their documented filters, `limit`, and `cursor`. Customer and supplier references require `includeArchived=false`; representative lookup can explicitly include archived records when needed.

```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.

## Opportunity finder

Use the opportunity finder for customer- and supplier-side pipeline work. It returns visible opportunity summaries with relationship, owner, product, status, estimate, and update context.

```bash
curl "$SHELFCYCLE_API_BASE_URL/opportunities?status=LEAD,IN_PROGRESS&assignedToId=user-id&sortDirection=desc&limit=50" \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
  -H "X-ShelfCycle-Client: Opportunity follow-up"
```

Narrow with matching text in `query`, one or more `status` or `assignedToId` values, an exact `customerId`, `supplierId`, `productId`, or `createdById`, or an ISO timestamp range using `createdFrom` and `createdTo`. Sort by `updatedAt` in ascending or descending order.

The response includes `meta.total` for the complete visible result and a signed `meta.nextCursor` when more rows are available. Continue with the cursor by itself. Fetch `GET /opportunities/{id}` after selecting a row to review metadata and the latest timeline activity.

## Commercial document finders

| Endpoint | Scope | Narrow with |
| --- | --- | --- |
| `GET /orders` | `orders:read` | `orderNo`, `customerOrderNo`, `externalId`, `customerId`, `productId`, `productFamilyId`, `linkedPurchaseOrderId`, `status`, creator, created time, a paired `fromDate`/`toDate` ordered-date range, or a paired `changedFrom`/`changedTo` range. |
| `GET /purchase-orders` | `purchase-orders:read` | `orderNo`, `externalId`, `supplierId`, `productId`, `productFamilyId`, `linkedSalesOrderId`, `status`, creator, created time, a paired `fromDate`/`toDate` due-date range, or a paired `changedFrom`/`changedTo` range. |

For exact identifier matching, sales-order `orderNo`, `customerOrderNo`, and `externalId` accept one value or as many as 25 comma-separated values. Purchase-order `orderNo` and `externalId` support the same batching. For example:

```text
GET /orders?customerOrderNo=A,B,C&limit=5
```

Order finders return up to 25 rows and a signed `nextCursor` when more results are available. Continue with the cursor alone so the original filters, ordering, and snapshot stay together.

Use paired `changedFrom` and `changedTo` for a half-open last-updated range of up to 30 days. Finder metadata reports the ordering, snapshot time, returned row count, and continuation cursor.

## Continue through multiple pages

Start each finder with its documented filters and `limit`. When `meta.nextCursor` is available, follow the continuation rule for that finder:

| Continuation | Finders | Next request |
| --- | --- | --- |
| Cursor only | Purchase Execution, Sales Orders, Purchase Orders, Suppliers, and Certification Types | Send only `cursor` with the exact returned value. Do not repeat filters or `limit`. |
| Repeat filters | Tags, Tagged Records, and Product Directory | Keep the original filters and `limit` unchanged, then add the exact returned `cursor`. |

Stop when `meta.nextCursor` is `null`. Use the limit documented for the selected endpoint; for example, Sales Orders, Purchase Orders, and Suppliers accept 1 through 25, while Purchase Execution and Certification Types accept 1 through 100.

If a request returns `doNotRetrySameRequest: true`, do not repeat it unchanged. Correct the filter, limit, or cursor from the returned error details. When a continuation cursor is no longer usable, restart from the original first-page request rather than trying to repair the cursor.

## 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 /opportunities/{id}
GET /contacts/{id}
GET /notes/{id}
GET /customers/{id}/documents
GET /suppliers/{id}/documents
GET /products/{id}/documents
```

Detail and attached document responses provide the fields documented for the selected record. Sales- and purchase-order detail returns 100 lines by default, accepts `lineLimit` up to 500, and supports consistent continuation through `lineCursor`. Continue with `lineCursor` alone.

> **Guardrail**: If a finder returns `finder_filter_required`, `unsupported_sync_filter`, or `doNotRetrySameRequest: true`, use the repair fields to choose a supported filter, date range, page size, or fresh first-page request.
