OpenShopy
Przewodnik

Shipping and fulfillment

Shipping zones

A zone is a named list of ISO 3166-1 alpha-2 country codes (for example Poland → PL, EU → DE, FR, CZ, …). A destination country should belong to one zone. New stores get Poland, European Union and Rest of world zones.

Shipping rates

Each zone has any number of rates:

FieldMeaning
rate_typeflat (always the same price), weight (limited by min_weight/max_weight in grams), price (limited by min_subtotal/max_subtotal in minor units)
priceShipping price in minor units of the store base currency
free_overOptional cart subtotal above which the rate becomes free
carrier_codeOptional carrier (inpost, dpd, dhl, gls, poczta_polska, orlen, ups, fedex, other)
is_pickupMarks local/parcel-locker pickup rates; the customer chooses a pickup location
delivery_days_min / delivery_days_maxShown to customers as an estimate
active, positionVisibility and order

At checkout the engine finds the zone for the shipping country, filters rates by total cart weight and subtotal, applies free_over and any free-shipping discount, and returns the available options in the cart quote.shipping_options (or GET /shipping/rates?country=PL&lines=<variant_id>:<qty>).

Local pickup

Create pickup locations (name, address, opening hours) in Shipping → Pickup locations. A pickup rate plus pickup_location_id on the cart lets the customer collect in person.

Carriers and tracking

Carriers have a tracking URL template with a {tracking_number} placeholder, for example:

text
https://inpost.pl/sledzenie-przesylek?number={tracking_number}

When a shipment is created with a carrier and a tracking number, the tracking URL is generated automatically, stored on the shipment and sent to the customer in the order shipped notification. You can also send any custom tracking URL.

Shipping labels

Automatic label generation through carrier APIs (InPost ShipX, DPD, DHL…) needs your own carrier contract and API credentials, so it is not switched on by default. Create the label in the carrier's panel and record the carrier and tracking number on the shipment — tracking links and customer notifications then work automatically.

Shipments and partial fulfillment

An order can have several shipments. Each shipment lists the order items and quantities it contains:

json
POST /orders/{id}/fulfillments
{
  "carrier_code": "inpost",
  "tracking_number": "620000000000000000000000",
  "items": [{ "order_item_id": "…", "quantity": 1 }],
  "notify": true
}
  • Omit items to ship everything that is still unshipped.
  • If some items remain unshipped, the order becomes fulfillment_status: "partial"; when everything is shipped it becomes fulfilled.
  • Shipment statuses: pending, label_created, in_transit (default), out_for_delivery, delivered, failed, returned. Update them with PATCH /fulfillments/:id.
  • When every shipment is delivered and the order is fully fulfilled and paid, the order becomes completed and the customer gets the order delivered message.

Returns

Record a return with the returned items, a reason and whether to restock (POST /orders/:id/returns). Returns move through requested → approved → received → refunded (or rejected). When a return is received, restocked items go back into inventory and are written to the inventory log; marking it refunded records the refund on the order.