Shipping providers

Local and external shipping adapter dispatch for rates, labels, validation, tracking, and cancellation.

The ShippingProvider model and features/keystone/utils/shippingProviderAdapter.ts support:

  • local modules shippo, shipengine and manual in features/integrations/shipping;
  • separately deployed HTTP adapter apps, set per operation.

There are five operation fields: getRatesFunction, validateAddressFunction, createLabelFunction, trackShipmentFunction and cancelLabelFunction. When a field starts with http, Openfront sends that URL a JSON POST with the provider and the operation arguments. Otherwise it imports the matching local file and calls the export with the field's name.

Operations and who can call them

MutationAdapter callPermission
getRatesForOrder(orderId, providerId, dimensions)ratescanReadOrders or canManageOrders
validateShippingAddress(providerId, address)validatecanReadOrders or canManageOrders
trackShipment(providerId, trackingNumber)trackcanReadOrders or canManageOrders
createProviderShippingLabel(orderId, providerId, rateId, dimensions, lineItems, idempotencyKey)labelcanManageFulfillments
cancelShippingLabel(providerId, labelId)cancelcanManageFulfillments

createProviderShippingLabel checks that each line has unfulfilled quantity, refuses inactive providers, and returns the existing label when the same idempotency key is retried. createOrderFulfillment and cancelOrderFulfillment record fulfillments without a carrier and also take an idempotency key and a reason respectively.

Data boundary

Shipping options define what customers can choose at checkout. Shipping providers, labels, fulfillments and fulfillment items record what was actually shipped. The callers read the provider's accessToken and send the provider record to the adapter. For an HTTP adapter, that app receives the access token and the order's address and line items.

The HTTP bridge sends a plain JSON POST. It has no timeout, request signature, destination allowlist or response schema. Restrict who can edit provider records, use HTTPS endpoints you control, and validate requests inside the adapter app.

Current gaps

  • The order-level "new provider" form stores an API URL in metadata.apiUrl and does not set any operation field.
  • The provider drawer's "Custom Provider" option sets every operation to the local name custom, but there is no custom.ts module, so calls fail.
  • Set URL operation fields on the generic /dashboard/shipping-providers editor instead.
  • The manual module is a placeholder. Its label function reads a rate argument while the dispatcher passes rateId, and it returns made-up tracking numbers and example.com label URLs.

A provider record existing does not mean its calls work. Run each operation you need.

Before enabling a provider

  1. Confirm each operation field points where you expect.
  2. Check that only trusted operators can read the access token or change the fields.
  3. Run rates, address validation, label purchase, tracking and cancellation in the carrier's sandbox.
  4. Retry a label purchase with the same idempotency key and confirm one label.

Manual fulfillment

Onboarding creates a manual fulfillment provider (fp_manual) for shipping options. Operators can record a fulfillment with an optional tracking number and carrier through createOrderFulfillment, without calling a carrier.

Start with Add a shipping adapter.

On this page