# External prices

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

If you want to use the external prices feature in a [market](https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/markets), fill in the market's `external_prices_url` field with your external service endpoint and make sure your service is compliant with the specifications described below.

### Fetching external prices

When you [add a line item](https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/line_items/create) to an order, set the `_external_price` attribute to `true` if you want the line item price to be provided by your external service, instead of Commerce Layer:

```shell
curl -g -X POST \
  'https://yourdomain.commercelayer.io/api/line_items' \
  -H 'Accept: application/vnd.api+json' \
  -H 'Authorization: Bearer your-access-token' \
  -H 'Content-Type: application/vnd.api+json' \
  -d '{
    "data": {
      "type": "line_items",
      "attributes": {
        "quantity": 2,
        "sku_code": "TSHIRTMM000000FFFFFFXLXX",
        "_external_price": true
      },
      "relationships": {
        "order": {
         "data": {
            "type": "orders",
            "id": "QWERtyUpBa"
          }
        }
      }
    }
  }'
```

Upon line item creation, Commerce Layer triggers a `POST` request to the specified `external_prices_url` endpoint, sending the line item payload (including the order) in the request body.

{% hint style="info" %}
Once the external price trigger is set for a line item, any following computation on that line item's price will be performed invoking your external endpoint. If, for some reason, you want to stop using the external service for the price computation and use the price from the market [price list](https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/price_lists) (or [price tier](https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/price_tiers)), you just need to `PATCH` the line item setting the `_external_price` trigger attribute to `false`.
{% 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** — `line_items` in this specific case — some **relationships** are also included to avoid useless API roundtrips:

* `order`
* `order.customer`
* `order.customer.tags`
* `order.line_items`
* `order.market`
* `item`

```json
{
  "data": {
    "id": "xYZkjABcde",
    "type": "line_items",
    "links": { ... },
    "attributes": {
      "quantity": 2,
      "sku_code": "TSHIRTMM000000FFFFFFXLXX",
      "_external_price": true
    },
    "relationships": { ... },
    "meta": { ... }
  },
  "included": [
    {
      "id": "wBXVhKzrnq",
      "type": "orders",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "bGvCXzYgNB",
      "type": "customers",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "YawgnfmKad",
      "type": "tags",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "hJnnKTGfRd",
      "type": "line_items",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "DvlGRmhdgX",
      "type": "markets",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "XGZwpOSrWL",
      "type": "skus",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    }
  ]
}
```

{% 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 line item's relationships within the `external_includes` attribute of the market 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 responds with a `422` status code by using the [response](#response) error message. 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 least the unit price computed by the external logic and the SKU code of the related product. 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>    "sku_code": "TSHIRTMM000000FFFFFFXLXX",
</strong><strong>    "unit_amount_cents": 4900,
</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 needed, you can specify in the response also the `compare_at_amount_cents` of the price, which should be greater than the `unit_amount_cents`. If not (i.e. if it's not specified or lower than the unit amount) it will be automatically set as equal to the `unit_amount_cents`.
{% endhint %}

{% 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 line item.
{% endhint %}

### SKUs availability

When you fetch a list of SKUs with a sales channel, you only get those SKUs that have a price defined in the market's price list and at least a stock item in one of the market stock locations.

{% hint style="info" %}
In case you manage prices externally, the price filter is not considered.
{% endhint %}

### Security

When you activate external prices, 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.

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