Read the catalog and resolve prices
A catalog integration normally needs three identifiers before it can create a commercial document:
product id → variant id → UOM id (when the seller uses multiple units)
Do not match only on a display name. Store the ARC ids and SKU alongside your external product mapping.
This page uses GraphQL with a staff login. A server-to-server connector holding a tenant API key reads the same ids, units and stored prices through the Service API's read endpoints.
Find the ids you need
Before creating any document, resolve the four ids it references. All of these queries are tenant-scoped to your credential:
# Customer for the document header
query FindCustomer($search: String) {
customers(search: $search) {
id
code
displayName
status
}
}
# Product + variant + the UOM the variant sells in
query FindVariant($search: String) {
products(filter: {search: $search, status: [ACTIVE]}, limit: 5) {
items {
id
name
sku
variants {
id
sku
name
salePrice
salesUOMId
isActive
}
}
}
}
# All units of measure, when you need to pick or verify a UOM
query Uoms {
getUOMs {
id
code
name
}
}
customers(search: …) returns a plain list — for large tenants use the cursor-paginated
customersPage(cursor, search, take) instead. When you only know a name or code and not the
entity kind, globalSearch(query: …) searches across documents and entities. It is a staff query that
requires products:product:read before it runs at all, then returns only the kinds your other
permissions can read (each kind needs its own read permission, e.g. payments:invoice:read for
invoices). It refuses customer-portal tokens. A portal or buyer
integration uses customerCatalogSearch(query: …), which returns storefront products, brands and
categories only.
List products
query Products($cursor: String, $filter: ProductFilterInput) {
products(
cursor: $cursor
limit: 50
filter: $filter
sort: { field: UPDATED_AT, order: DESC }
) {
items {
id
name
sku
status
updatedAt
variants {
id
sku
name
salePrice
isActive
salesUOMId
minOrderQuantity
maxOrderQuantity
}
}
nextCursor
hasNextPage
totalCount
}
}
The exact enum values for ProductSortInput are in the reference. If your client does not need sorting, omit sort rather than guessing an enum.
Supported product filters include search, category, brand, status, tags, stock, price bounds, and updatedAfter. Use updatedAfter plus a stable checkpoint for incremental catalog syncs, but always allow for edits that arrive around the checkpoint boundary.
Read variant-level detail
The product list projection may not include the full price ladder. Use the variant/detail operations when you need UOMs, stock, or quantity-break prices:
query VariantDetail($productId: ID!) {
productVariants(productId: $productId) {
id
productId
sku
name
isActive
isDefault
salePrice
salesUOMId
minOrderQuantity
maxOrderQuantity
totalStock
totalReserved
totalAvailable
}
}
The available fields and whether a projection is populated can change with the selected operation. Use the generated type page for the current contract.
Read order rules per unit
ProductVariant has no order-multiple field. Order multiples, and the minimum and maximum order quantity for each pack, are set per sales unit of measure. Read them with getProductUOMs, scoped to the variant:
query VariantUnits($productId: String!, $variantId: String) {
getProductUOMs(productId: $productId, variantId: $variantId) {
uomId
isSales
minOrderQty
maxOrderQty
orderMultiple
conversionFactor
}
}
Use the rows where isSales is true. getProductUOMs is role-gated: the caller's me.role must be ADMIN, MANAGER, WAREHOUSE_STAFF, VIEWER or SALES_REP. A user whose role is OWNER is refused.
Resolve a quantity price
For a basic quantity-price preview, ARC exposes:
query VariantPrice(
$variantId: ID!
$quantity: Int!
$customerTier: String
) {
calculateVariantPrice(
variantId: $variantId
quantity: $quantity
customerTier: $customerTier
) {
isValid
originalPrice
price
discount
tierName
}
}
For partner-specific, UOM-specific, or currency-specific work, use the operation exposed by the current schema/reference or the MCP get_pricing_context tool. The API's canonical pricing service is the authority; a client-side copy will eventually diverge.
Product sync strategy
- Page
productswith the returned cursor. - Upsert by ARC product/variant id in your database.
- Save
updatedAt, SKU, active status, and UOM mapping. - On the next run, use
updatedAfterwith a small overlap window and de-duplicate by id + updated timestamp. - Re-read price at order/quote time. A catalog sync is not a price lock.
What not to do
- Do not use the
salePricefrom an old catalog sync as the final quote price. - Do not send a tenant id to fetch another catalog.
- Do not treat inactive products or variants as orderable.
- Do not infer UOM conversion from a product name or SKU.
- Do not calculate tax or promotion discounts outside ARC.
Next: Quote to cash.