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.
interface ShippingRateOutput { rates: ShippingRate[];}interface ShippingRate { name: string; // Required — shown as the radio label price: number; // Required — in display currency. 0 = free currency?: string; // Defaults to the cart currency description?: string; // Sub-line under the name code?: string; // Internal id, helpful for tracking // Optional — what kind of fulfillment this rate represents. Defaults // to "standard". Local pickup and pickup point rates render with an // extra indicator strip under the radio label. kind?: 'standard' | 'local_pickup' | 'pickup_point'; pickup?: { location_id?: string; // For local_pickup — your warehouse / store provider?: string; // For pickup_point — e.g. "DHL", "UPS Access Point" address?: { address1?: string; city?: string; province?: string; country?: string; zip?: string; }; window?: string; // Free-text, e.g. "Mon–Fri 10am–6pm" };}
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.
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.
Shipping Method━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━○ Standard Shipping — ₹49.00 ← Merchant zone○ Express Shipping — ₹149.00 ← Merchant zone Powered by Custom Shipping○ Same-Day Delivery — ₹299.00 ← Your function○ Pickup at Store — FREE ← Your function
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.
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.
Return early when destination is unknown
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.
Provide fallbacks for carrier API outages
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.
Test against the real checkout
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.