Pricing
Fetching, caching, and displaying customer-specific pricing.
Pricing Guide
The pricing service calculates customer-specific prices based on P21 pricing libraries, quantity breaks, and customer rules. You send a customer ID, item ID, and quantity — the service returns a unit price.
Getting a Price
Server Action
import { createSiteActions } from "@simpleapps-com/augur-server";
const actions = createSiteActions(api, {
defaultCustomerId: process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_ID,
pricing: { redisTtl: 3600 },
});
const price = await actions.pricing.getItemPrice("ITEM-123", customerId, 1);
// price.unitPrice → 42.50Client Hook
import { useItemPrice } from "@simpleapps-com/augur-hooks";
function ItemPrice({ itemId, customerId }) {
const { data, isLoading } = useItemPrice(itemId, customerId, 1);
if (isLoading) return <Skeleton />;
if (!data?.unitPrice) return <span>Call for Price</span>;
return <span>${data.unitPrice}</span>;
}When unitPrice is 0, the item requires a quote — display "Call for Price" or similar.
API Route
For non-React consumers, expose pricing as an API route:
// app/api/pricing/[itemId]/route.ts
export async function GET(req, { params }) {
const { itemId } = params;
const customerId = getCustomerIdFromSession(req);
const price = await pricingActions.getItemPrice(itemId, customerId);
return Response.json(price, {
headers: { "Cache-Control": "max-age=600, stale-while-revalidate=3600" },
});
}Bulk Pricing
For search results and product listings, fetch prices for multiple items in one call:
const prices = await actions.pricing.batchGetItemPrices(
["ITEM-1", "ITEM-2", "ITEM-3"],
customerId,
1,
);
// prices["ITEM-1"].unitPrice → 42.50
// prices["ITEM-2"].unitPrice → 18.99Graceful Fallback Pattern
In product cards, use batch data when available and fall back to individual fetches:
function ProductCard({ item, batchedPriceData }) {
const { data: individualPrice } = useItemPrice(
item.itemId,
customerId,
1,
{ enabled: !batchedPriceData },
);
const price = batchedPriceData ?? individualPrice;
return <Price value={price?.unitPrice} uom={item.unitOfMeasure} />;
}This ensures prices appear immediately when batch data is ready, while individual cards still load their own prices if the batch hasn't completed.
Displaying Prices
Use createPrice from augur-web for consistent formatting:
// lib/price.ts
import { createPrice } from "@simpleapps-com/augur-web/price";
export const { Price, formatPrice } = createPrice({
precision: 2,
zeroLabel: "Call for Price",
classNames: {
uom: "text-sm uppercase text-primary-1",
separator: "text-primary-1",
},
});Price Component
For product cards and detail pages — handles loading state and UOM display:
<Price value={unitPrice} uom="EACH" loading={isLoading} />
// Renders: "$42.50 / EACH" or "Call for Price" or a skeletonformatPrice Function
For cart totals, line items, and anywhere you need a formatted string:
formatPrice(42.50) // "$42.50"
formatPrice(unitPrice, { quantity: 5 }) // "$212.50" (extended price)useFormatPrice Hook
Alternative hook-based approach from augur-hooks:
import { useFormatPrice } from "@simpleapps-com/augur-hooks";
const { formatPrice } = useFormatPrice();Server-Side Prefetching
Prefetch pricing on the server for instant page loads:
// app/items/[itemId]/page.tsx
import { getQueryClient } from "@simpleapps-com/augur-hooks/server";
import { getItemPriceOptions } from "@simpleapps-com/augur-hooks/server";
import { dehydrate, HydrationBoundary } from "@tanstack/react-query";
export default async function ItemPage({ params }) {
const queryClient = getQueryClient();
await queryClient.prefetchQuery(
getItemPriceOptions(api, params.itemId, customerId, 1),
);
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<ItemDetail itemId={params.itemId} />
</HydrationBoundary>
);
}Caching Strategy
| Layer | TTL | Notes |
|---|---|---|
| Cloudflare edge | 2 hours | Default edgeCache for pricing actions |
| Redis | 1 hour | Server-side withServerCache |
| React Query | Managed by hooks | Stale time from cache config |
| API route | 10 min + 1 hour SWR | HTTP cache headers |
Prices sync from P21 every 5–15 minutes. Edge and Redis caching are safe because price changes propagate on the same cycle.