Shipping
Three-level model:
shipping_zones countries + zip patterns, optional market scope
└── shipping_methods carrier × service (PPL Home, Zásilkovna pickup)
└── shipping_rates tiered per (weight × subtotal × quantity)
Plus a global cache of pickup points (carrier_pickup_points).
Zones
A zone is a destination filter — country codes + optional zip-pattern matching. Zones can be account-wide or scoped to one market.
curl -X POST "$API/shipping/zones.json" \
-H "Authorization: Bearer $NEVIOS_KEY" -H "Content-Type: application/json" \
-d '{
"handle": "cz",
"name": "Česká republika",
"country_codes": ["CZ"],
"zip_patterns": ["1*", "2*"]
}'
zip_patterns accept prefix wildcards (12* matches 12000) or
exact strings.
Methods
A method is one shipping option (PPL Home, Zásilkovna pickup, GLS Express). It binds to a zone and configures carrier behavior.
curl -X POST "$API/shipping/methods.json" \
-H "Authorization: Bearer $NEVIOS_KEY" -H "Content-Type: application/json" \
-d '{
"handle": "zasilkovna-pickup",
"name": "Zásilkovna výdejní místo",
"zone_id": 308...,
"carrier": "zasilkovna",
"service_code": "Z_BOX",
"rate_mode": "tiered",
"requires_pickup_point": true,
"is_cod_compatible": true,
"estimated_days_min": 1,
"estimated_days_max": 2,
"cod_fee_cents": 3000,
"carrier_config": { "shop_id": "..." }
}'
rate_mode is flat | tiered | carrier_api | free. carrier_api
calls the carrier in real time at quote — Phase 1 supports static
tiered rates only; carrier_api is a slot for future iterations.
Rates
A rate is one tier on a method. Bind it to a method and add weight / subtotal / quantity bounds:
# Standard tier
curl -X POST "$API/shipping/methods/{method_id}/rates.json" \
-H "Authorization: Bearer $NEVIOS_KEY" -H "Content-Type: application/json" \
-d '{
"price_cents": 9900,
"currency": "CZK",
"max_weight_grams": 5000,
"display_name": "Standard"
}'
# Free shipping above 2000 CZK
curl -X POST "$API/shipping/methods/{method_id}/rates.json" \
-H "Authorization: Bearer $NEVIOS_KEY" -H "Content-Type: application/json" \
-d '{"price_cents":0,"currency":"CZK","min_subtotal_cents":200000}'
is_free is a Postgres GENERATED ALWAYS column (price_cents = 0)
— don't set it in the request, it's computed.
Quote
The quote endpoint returns all rate options for an order's destination
- cart shape:
curl -X POST "$API/shipping/quote.json" \
-H "Authorization: Bearer $NEVIOS_KEY" -H "Content-Type: application/json" \
-d '{
"country_code": "CZ",
"zip": "15000",
"weight_grams": 1500,
"subtotal_cents": 50000,
"currency": "CZK"
}'
{
"quotes": [
{
"method": { "handle": "ppl-home", "name": "PPL doručení", ... },
"rate_id": "308...",
"price_cents": "9900",
"currency": "CZK",
"is_free": false,
"display_name": "Standard"
},
...
]
}
The storefront calls
GET /storefront/2026-01/checkouts/{token}/shipping_quote.json for
the same data computed against the checkout's known shipping address
and cart contents.
Pickup points
Methods with requires_pickup_point=true need a chosen pickup point
at checkout. The system maintains a global cache at
carrier_pickup_points (no RLS — public reference data per carrier).
curl "/admin/2026-01/shipping/pickup-points.json?carrier=zasilkovna&country_code=CZ&postcode_prefix=110&limit=10" \
-H "Authorization: Bearer $NEVIOS_KEY"
The storefront passes pickup_point_id when calling
PUT /storefront/2026-01/checkouts/{token}/shipping.json.
Endpoints
POST /admin/2026-01/{handle}/shipping/zones.json
POST /admin/2026-01/{handle}/shipping/methods.json
POST /admin/2026-01/{handle}/shipping/methods/{id}/rates.json
DELETE /admin/2026-01/{handle}/shipping/methods/{id}.json
DELETE /admin/2026-01/{handle}/shipping/rates/{id}.json
POST /admin/2026-01/{handle}/shipping/quote.json
GET /admin/2026-01/shipping/pickup-points.json (global)
Next: Tax.