External shipping costs

How to manage shipping methods cost via external services

Sometimes, you can decide not to manage the price of a shipping method within Commerce Layer but use an external service instead. You may want to do that in order to support more dynamic or custom shipment pricing or just leverage an existing service that you want to keep as your system of records.

If you want to use the external shipping cost feature for one (or more) of your shipping methods, fill in the shipping method's external_prices_url field with your external service endpoint and make sure your service is compliant with the specifications described below.

Fetching external shipping method costs

Set the scheme attribute to external if you want the shipping method's price to be provided by your external service, overriding the shipping method's price_amount_cents you set at creation time. Also, remember to specify the external_prices_url if you haven't already set it via the dashboard UI when creating the shipping method:

curl -g -X PATCH \
  'https://yourdomain.commercelayer.io/api/shipping_methods/QWERtyUpBa' \
  -H 'Accept: application/vnd.api+json' \
  -H 'Authorization: Bearer your-access-token' \
  -H 'Content-Type: application/vnd.api+json' \
  -d '{
  "data": {
    "type": "shipping_methods",
    "id": "QWERtyUpBa",
    "attributes": {
      "scheme": "external",
      "external_prices_url": "https://external_prices.yourbrand.com"

When the external shipping method is associated with a shipment, Commerce Layer triggers a POST request to the specified external_prices_url endpoint, sending the shipment payload (including the shipping method) in the request body.

For performance reasons, when fetching the available shipping methods for an order the price is not updated with the value calculated externally which is fetched only when the shipping method is selected.


The request payload is a JSON:API-compliant object you can query to perform your own computation. Aside from the target resourceshipments in this specific case — the associated shipping method is also included as a relationship:

    "links":{ ... },
      "number": "#1234/S/001",
      "status": "draft",
      "currency_code": "EUR",
      "cost_amount_cents": 1000,
      "cost_amount_float": 10.0,
      "formatted_cost_amount": "€10,00",
      "skus_count": 2,
      "selected_rate_id": "rate_f89e4663c3ed47ee94d37763f6d21d54",
      "rates":[ ... ],
      "get_rates_errors":[ ... ],
      "get_rates_started_at": "2018-01-01T12:00:00.000Z",
      "get_rates_completed_at": "2018-01-01T12:00:00.000Z",
      "purchase_started_at": "2018-01-01T12:00:00.000Z",
      "purchase_completed_at": "2018-01-01T12:00:00.000Z",
      "purchase_failed_at": "2018-01-01T12:00:00.000Z",
      "created_at": "2018-01-01T12:00:00.000Z",
      "updated_at": "2018-01-01T12:00:00.000Z",
      "reference": "ANY-EXTERNAL-REFEFERNCE",
      "reference_origin": "ANY-EXTERNAL-REFEFERNCE-ORIGIN",
      "metadata":{ ... }
    "relationships":{ ... },
    "meta":{ ... }
  "included": [
      "id": "wBXVhKzrnq",
      "type": "shipping_methods",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }

In case the call to your external endpoint goes timeout, responds with an internal server error, or is blocked by the open circuit breaker, the API keeps responding with a 200 OK status code. The default shipping price is used (if any) and the circuit breaker internal counter (if closed) is incremented.


Your service response (or error) must match the format described in the example below.


The successful response must be a JSON object, returning the shipping method's price computed by the external logic, along with some additional information and metadata:

  "success": true,
  "data": {
    "price_amount_cents": 1700,
    "metadata": {
      "foo": "bar"


When you activate external shipping method costs, a shared secret is generated at the market level. We recommend verifying the callback authenticity by signing the payload with that shared secret and comparing the result with the callback signature header.

pageCallbacks security

Last updated