# External shipping costs

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](https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/shipping_methods)'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:

<pre class="language-bash"><code class="lang-bash">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": {
<strong>      "scheme": "external",
</strong><strong>      "external_prices_url": "https://external_prices.yourbrand.com"
</strong>    },
  }
}'
</code></pre>

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 associated shipping method and order) in the request body.

{% hint style="info" %}
For performance reasons, when [fetching the available shipping methods](https://app.gitbook.com/s/-Lk-ezuDClaMavTqnRi0/placing-orders/checkout/selecting-a-shipping-method#1.-get-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](https://app.gitbook.com/s/-Lk-ezuDClaMavTqnRi0/placing-orders/checkout/selecting-a-shipping-method#3.-select-a-shipping-method).
{% endhint %}

### Request

The request payload is a [JSON:API](https://jsonapi.org)-compliant object you can query to perform your own computation. Aside from the **target resource** — `shipments` in this specific case — the associated shipping method and order are also included as a relationship:

<pre class="language-json"><code class="lang-json">{
  "data":{
    "id":"pMeKKdCwez",
<strong>    "type":"shipments",
</strong>    "links":{ ... },
    "attributes":{
      "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":[ ... ],
      "purchase_error_code":null,
      "purchase_error_message":null,
      "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",
<strong>      "type": "shipping_methods",
</strong>      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "fXCNrSklry",
<strong>      "type": "orders",
</strong>      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    }
  ]
}
</code></pre>

{% hint style="info" %}
If needed, you can [overwrite the default list](https://docs.commercelayer.io/core/external-resources/..#custom-include-list) of included resources by passing your custom list of shipment's relationships within the `external_includes` attribute of the shipping method at creation or update time (nested relationships are allowed using dot notation).
{% endhint %}

{% hint style="warning" %}
In case the call to your external endpoint goes timeout, responds with an internal server error, or is blocked by the open [circuit breaker](https://docs.commercelayer.io/core/external-resources/..#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.
{% endhint %}

### Response

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

#### Example

{% tabs %}
{% tab title="Response" %}
The successful response must be a JSON object, returning at leat the shipping method's price computed by the external logic. If needed, you can optionally enrich the response with some additional information, notification messages, and metadata:

<pre class="language-json"><code class="lang-json">{
  "success": true,
  "data": {
<strong>    "price_amount_cents": 1700,
</strong>    "messages": [ ... ],
    "metadata": {
      "foo": "bar"
    }
  }
}
</code></pre>

{% endtab %}

{% tab title="Error" %}
On error, you must respond with an HTTP code >= `400`. The response body must be a JSON object containing any other relevant error code and message:

```json
{
  "success": false,
  "error": {
    "code": "YOUR-ERROR-CODE",
    "message": "Your error message"
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
If you specify the `messages` key a [notification](https://docs.commercelayer.io/core/external-resources/..#notifications) with the related information is automatically attached to the patched shipping method.
{% endhint %}

### Security

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

{% content-ref url="../callbacks-security" %}
[callbacks-security](https://docs.commercelayer.io/core/callbacks-security)
{% endcontent-ref %}
