Skip to content

Product Lookup

Product lookup enables field users to quickly retrieve product information by scanning barcodes during sales order creation. The feature supports multiple barcode formats and integrates with the offline-first architecture to ensure reliable operation in low-connectivity environments.

Primary use case: Sales representatives scan product barcodes to auto-add items to cart when creating sales orders.

GET /app/v1/products/barcode/:barcode
Authorization: Bearer <token>

Path Parameters:

ParamTypeDescription
barcodestringProduct barcode (EAN-13, UPC, Code-128)

Query Parameters:

None

GET /app/v1/products/barcode/8991234567890
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
{
"data": {
"id": 123,
"name": "Coca Cola 330ml",
"sku": "COKE-330",
"barcode": "8991234567890",
"brand": "Coca Cola",
"unit_price": 5000,
"category": "Beverages",
"active": true
},
"message": "product retrieved",
"code": "PRODUCT_BARCODE_DETAIL"
}

Product Not Found:

HTTP/1.1 404 Not Found
{
"success": false,
"message": "Product not found",
"code": "PRODUCT_BARCODE_NOT_FOUND"
}

Invalid Barcode Format:

HTTP/1.1 400 Bad Request
{
"success": false,
"message": "Invalid barcode format",
"code": "PRODUCT_BARCODE_INVALID"
}
export function useProductByBarcodeQuery(barcode: string) {
const profile = useAtomValue(profileAtom);
return useQuery({
queryKey: ['product', 'barcode', barcode],
queryFn: () => productService.getByBarcode(barcode),
enabled: !!barcode && !!profile,
networkMode: 'offlineFirst',
staleTime: 5 * 60 * 1000, // 5 minutes
select: (res) => res?.data?.data,
});
}
function CreateSalesOrderScreen() {
const [scannedBarcode, setScannedBarcode] = useState<string | null>(null);
const { data: product, isLoading } = useProductByBarcodeQuery(scannedBarcode || '');
const handleScanResult = useCallback((code: string) => {
setScannedBarcode(code);
// Auto-add to cart when product loaded
}, []);
useEffect(() => {
if (product) {
addToCart(product, 1);
setScannedBarcode(null); // Reset for next scan
}
}, [product]);
return (
<View>
<Button onPress={() => navigate('camera', { enableScan: true })}>
Scan Barcode
</Button>
{isLoading && <Text>Looking up product...</Text>}
</View>
);
}
interface CommonCameraProps {
mode: 'scan' | 'photo';
enableScan?: boolean;
onScanResult?: (barcode: string) => void;
onPhotoTaken?: (uri: string) => void;
}
// Usage
<CommonCamera
mode="scan"
enableScan={true}
onScanResult={handleScanResult}
/>
// From sales order screen
function handleOpenScanner() {
navigation.navigate('camera', {
mode: 'scan',
enableScan: true,
onScanResult: (code) => {
handleScanResult(code);
navigation.goBack();
},
});
}

The camera scanner supports the following formats:

FormatDescriptionCommon Use
EAN-1313-digit European Article NumberRetail products
EAN-88-digit EAN (small packages)Small items
UPC-A12-digit Universal Product CodeUS products
Code-128Alphanumeric barcodeLogistics, inventory
QR Code2D matrix codeURLs, complex data

Note: Product barcodes in Merq are typically EAN-13 or UPC-A.

  • staleTime: 5 minutes
  • cacheTime: 1 hour
  • networkMode: offlineFirst
  1. First scan (online): Fetch from API, cache result
  2. Same barcode scan (offline): Return cached result
  3. Same barcode scan (after 5 min): Try fetch, fall back to cache if offline
// After product update (admin only)
queryClient.invalidateQueries({
queryKey: ['product', 'barcode'],
});