Skip to main content

Shipping Rate Functions

A shipping_rate function returns extra shipping options for the customer to pick at checkout. They render under the merchant’s configured shipping zones with your appName attribution and the customer can select them exactly like a built-in rate. Runs at both cart verification (cart preview) and order placement for parity. The customer’s selection is sent back to the order as payload.customShippingRate.

How It Works

Function Manifest

Input Schema

All prices are in display currency units, not minor units (cents). price: 19.99 means ₹19.99 / $19.99 — return your shipping prices the same way.

Output Schema

Pickup variants

Return kind: 'local_pickup' when the customer collects from a store location. Set pickup.location_id to the warehouse/store gid. The checkout renders a “Local pickup” label and shows the address. Return kind: 'pickup_point' when handing off to a third-party network (parcel lockers, retail partners). Set pickup.provider to the network name. The checkout renders “Pickup point — <provider>” and shows the address and pickup window.
Each rate is decorated by the platform with:
and surfaces on the checkout in the verified-cart response’s customShippingRates. The cart UI groups them by appId so a single app’s rates appear under a shared “Powered by <appName>” header.

Examples

Free shipping above a threshold

Zone-based pricing

Third-party carrier proxy

How it renders in the UI

The customer can select any rate (merchant or app). When an app rate is selected, the frontend posts customShippingRate at order placement; the backend uses that price for the order total instead of the zone price.

Best Practices

Return price in the same currency the cart is using (input.cart.currency). Mismatched currencies log a warning and the rate may be applied without FX conversion.
On early cart-verification calls before the customer has typed their address, destination.country may be empty. Return { rates: [] } in that case to avoid surfacing a wrong rate.
Apps that proxy to carrier APIs should keep a static “best-guess” rate available. If your function throws or returns no rates, the customer only sees the merchant’s zones.
Drive /checkout on a development store with a headless browser and confirm your rate appears under the “Powered by <appName>” header. JSON-only tests are not proof — only the rendered radio is.

See Also