Shipping Configuration
Configure shipping rates, carriers, and the warehouse origin address
Shipping Configuration
The shipping system in Jose Madrid Salsa uses a multi-tier strategy: real carrier API rates with fallback to estimate-based rates, ensuring checkout is never blocked.
How Shipping Calculation Works
The calculateShipping function in lib/shipping-calculator.ts follows this strategy:
Resolve the Warehouse Origin
Every quote needs an origin. getShippingOrigin() reads the admin setting first, then the
SHIPPING_ORIGIN_* environment variables, and returns nothing rather than a placeholder when the
address is incomplete — an unresolved origin falls back to flat-rate estimates instead of pricing
from a made-up address.
const origin = await getShippingOrigin()
if (!origin.ok) {
console.error(describeMissingOrigin(origin.missing))
return calculateEstimateRates(input, true)
}Call Carrier API
For domestic orders under the threshold, the system calls the carrier API with calculated parcel dimensions:
const parcel = calculateParcelDimensions(items)
const shipmentRequest: ShipmentRequest = {
fromAddress: DEFAULT_ORIGIN_ADDRESS,
toAddress: { ... },
parcel,
}
const ratesResponse = await getShippingRates(shipmentRequest)Filter and Sort Rates
Rates are filtered based on address type (PO Box addresses only get USPS options) and sorted by cost:
if (isPoBox) {
filteredRates = ratesResponse.rates.filter((rate) =>
rate.carrier.toUpperCase().includes('USPS')
)
}
const sortedRates = [...filteredRates].sort((a, b) => a.rate - b.rate)Fallback to Estimates
If the API fails or returns no rates, the system falls back to estimate-based rates to never block checkout:
catch (error) {
console.error('[Shipping Calculator] Error:', error)
return calculateEstimateRates(input, true)
}Shipping Rate Configuration
Rates come from the ShippingSettings singleton where a store has set them, and fall back
field-by-field to the built-in defaults in lib/shipping/rate-config.ts:
export const DEFAULT_RATE_CONFIG: ShippingRateConfig = {
flatRateCents: 699,
weightSurchargeBaseCents: 499,
weightSurchargePerLbCents: 50,
weightSurchargeThresholdLb: 5,
internationalRateCents: 2499,
stateSurcharges: { AK: 1.5, HI: 1.5, PR: 2.0 },
}These are carriage only. A flat $4.00 packaging-and-materials fee
(lib/shipping/handling-fee.ts) is added once per order to every customer-facing quote — live
carrier rates included — so what the customer actually sees is:
| Method | Carriage | Customer pays |
|---|---|---|
| Standard domestic | $6.99 | $10.99 |
| International | $24.99 | $28.99 |
The fee is not scaled by the state surcharge or the weight surcharge, which price carriage rather
than packaging. The admin label routes call getShippingRates directly and do not include it —
buying postage is a cost, not a quote.
Origin Address Configuration
Set the shipping origin via environment variables:
SHIPPING_ORIGIN_ADDRESS="123 Main St"
SHIPPING_ORIGIN_CITY="San Francisco"
SHIPPING_ORIGIN_STATE="CA"
SHIPPING_ORIGIN_ZIP="94111"
SHIPPING_API_KEY="..." # Carrier API keyPO Box Detection
The system automatically detects PO Box addresses and restricts shipping options to USPS-only:
function isPOBox(address: string | undefined): boolean {
const patterns = [
/\bP\s*O\s+BOX\b/,
/\bPOST\s+OFFICE\s+BOX\b/,
/^\s*BOX\s+\d+/,
]
return patterns.some(p => p.test(address.toUpperCase()))
}Address Validation
Use the built-in validation before submitting shipping requests:
import { validateShippingAddress } from '@/lib/shipping-calculator'
const result = validateShippingAddress({
address1: '123 Main St',
city: 'San Francisco',
state: 'CA',
postalCode: '94111',
country: 'US',
})
if (!result.valid) {
console.error(result.errors)
// ["State must be a 2-letter code (e.g., CA, NY)"]
}Frontend Shipping Estimates
For real-time shipping previews, use the lightweight estimate function:
import { getShippingEstimate } from '@/lib/shipping-calculator'
const estimate = await getShippingEstimate({
subtotal: 35.00,
state: 'CA',
country: 'US',
})
// Returns: 10.99 — the $6.99 carriage plus the $4.00 packaging fee.
// Shipping is charged on every order, and the preview matches what checkout will charge.Parcel Dimensions
The system calculates parcel dimensions from order items:
- Weight: Sum of all item weights (defaults to 1 lb per item), converted to ounces
- Length/Width: Maximum dimensions across items
- Height: Sum of heights, capped at 24 inches
Weight Defaults
If a product has no weight set in the database, the calculator defaults to 1 pound per item. Set accurate weights in the product editor for better rate accuracy.
Key Files
How is this guide?
Last updated on