Augur

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

Client 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.99

Graceful 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 skeleton

formatPrice 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

LayerTTLNotes
Cloudflare edge2 hoursDefault edgeCache for pricing actions
Redis1 hourServer-side withServerCache
React QueryManaged by hooksStale time from cache config
API route10 min + 1 hour SWRHTTP cache headers

Prices sync from P21 every 5–15 minutes. Edge and Redis caching are safe because price changes propagate on the same cycle.