# External resources

Commerce Layer lets you manage some resources (i.e. prices, promotions, payment gateways, tax calculators, and more to come) from the outside of the platform itself, using an external service of your choice or a serverless function.

In order to get the data from the external source, when needed, we trigger a `POST` request to the endpoint that you specified. The request contains a JSON payload that will be detailed case by case, along with the successful response (or error) format we expect to receive back.

When you create a new external resource, a **shared secret** is generated. It will be used each time we send data to the specified endpoint to sign the payload. The signature will be stored in the **X-CommerceLayer-Signature** [header](#request-headers) so that you can verify the callback authenticity and consider it reliable.

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

## Circuit breaker

All the external resources are subject to a circuit breaker check: if the call to your external endpoint fails consecutively more than **30** times, the circuit breaker opens and any further request to the resource will be skipped.

{% hint style="warning" %}
An open circuit for an external resource might result in a `422` error in some specific cases (e.g. [external prices](https://docs.commercelayer.io/core/external-resources/external-prices)), but it is usually ignored with a `200 OK` response status to avoid accidental side effects on the order lifecycle.
{% endhint %}

### Resetting the circuit

The circuit is automatically reset anytime a call to your external endpoint succeeds before reaching the counter's threshold.

You can also reset the circuit manually by passing the `_reset_circuit` trigger attribute (you must use [integration](https://docs.commercelayer.io/core/api-credentials#integration) API credentials). This is also your only option in case the circuit is stuck in the open state:

```shell
curl -g -X PATCH \
  'https://yourdomain.commercelayer.io/api/external_gateways/bGHfCxZJKl' \
  -H 'Accept: application/vnd.api+json' \
  -H 'Authorization: Bearer your-access-token' \
  -H 'Content-Type: application/vnd.api+json' \
  -d '{
    "data": {
      "type": "external_gateways",
      "id": "bGHfCxZJKl",
      "attributes": {
        "_reset_circuit": true
      }
    }
  }'
```

{% hint style="info" %}
You'll be notified via email every time the circuit breaker counter reaches **10** consecutive failures, as an early warning. Another notification is sent when the circuit breaker opens.
{% endhint %}

## Payload format

The request payload sent to an external endpoint has the same format that you get when fetching a resource through the REST API, with some relevant resources included.

```json
  "data": {
    "id": "resource-id",
    "type": "resource-type",
    "links": { ... },
    "attributes": {...},
    "relationships": { ... },
    "meta": { ... }
  },
  "included": [
    {
      "id": "included-resource-id",
      "type": "included-resource-type",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    { ... }
  ]
}
```

## Custom include list

As you can see from the [sample payload](#payload-format) above, some relationships are included by default in the request payload (please refer to the specific resource for the complete list). If you need to specify a custom list of relationships that will be included in the payload, you can **overwrite the default list** by passing it into the `external_includes` attribute of the related external resource at creation or update time (here below an example related to the creation of an [external tax calculator](https://docs.commercelayer.io/core/external-resources/external-tax-calculators) with a custom include list):&#x20;

<pre class="language-bash"><code class="lang-bash">curl -g -X POST \
  'https://yourdomain.commercelayer.io/api/external_tax_calculators' \
  -H 'Accept: application/vnd.api+json' \
  -H 'Authorization: Bearer your-access-token' \
  -H 'Content-Type: application/vnd.api+json' \
  -d '{
    "data": {
      "type": "external_tax_calculators",
      "attributes": {
        "name": "My tax calculator",
        "tax_calculator_url": "https://external_calculator.yourbrand.com",
<strong>        "external_includes": [ "line_items", "line_item_options", "line_items.item" ]
</strong>      }
    }
  }'
</code></pre>

{% hint style="info" %}

#### Allowed includes based on the target resource

When specifying custom included resources, always reference the target resource required by the external request:

* The **order** for [external promotions](https://docs.commercelayer.io/core/external-promotions#request) and [external tax calculators](https://docs.commercelayer.io/core/external-tax-calculators#request).
* The **shipment** for [external shipping costs](https://docs.commercelayer.io/core/external-shipping-costs#request).
* The **line item** for [external prices](https://docs.commercelayer.io/core/external-prices#request) (in this case, the custom includes must be defined at the **market** level to avoid specifying a custom list for each single line item).
* The specific **transaction** for [external payment gateways](https://docs.commercelayer.io/core/external-payment-gateways#request).

External includes are not supported for [external order validation](https://docs.commercelayer.io/core/external-resources/external-order-validation). Providing an invalid include for the target resource will result in an error.
{% endhint %}

{% hint style="warning" %}
We strongly recommend limiting the number of included relationships to **a maximum of 10**. Otherwise, the payload will be too large and your external callback could struggle to parse it within the maximum allowed timeout window.
{% endhint %}

{% hint style="danger" %}
If the resource `external_includes` array is populated the provided list **overrides** the default one. The two lists are **not merged**. This means that if you want to add custom includes to the default list, you need to specify a new list containing the default includes plus the new ones.
{% endhint %}

## Response format

The response we require from the external endpoint is a JSON featuring the outcome of the operation, along with some data and error information (if any), based on what type of external resource is involved.

{% tabs %}
{% tab title="Success" %}
In case of success, you can add additional info by populating the response `metadata` object and `messages` array (that information will be stored respectively in the resource's `metadata` attribute and associated `notifications` relationship):

```json
{
  "success": true,
    "data": {
      ...
      "messages": [ ... ],
      "metadata": {
        "foo": "bar"
     }
  }
}
```

{% endtab %}

{% tab title="Error" %}
In case of error, you must respond with an HTTP code >= `400`. You can populate the error object with any other relevant `code` and `message` and add an additional `messages` array that will be stored in the resource's associated `notifications` relationship:

```json
{
  "success": false,
  ...
  "error": {
    "code": "YOUR-ERROR-CODE",
    "message": "Your error message"
  },
  "data": {
    "messages": [ ... ]
  }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Any external endpoint has **3 seconds** to respond before being timed out.
{% endhint %}

## Notifications

All the external resources, with the exception of external order validation, can automatically add [notifications](https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/notifications) to the resource they are called for (for example external promotions can add notifications directly to the order on which they are performing the computation, external prices on the patched line item, etc.), as listed in the table below:

<table><thead><tr><th data-type="content-ref">External resource</th><th data-type="content-ref">Notified resource</th></tr></thead><tbody><tr><td><a href="external-resources/external-order-validation">external-order-validation</a></td><td></td></tr><tr><td><a href="external-resources/external-prices">external-prices</a></td><td><a href="https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/line_items">Line items</a></td></tr><tr><td><a href="external-resources/external-shipping-costs">external-shipping-costs</a></td><td><a href="https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/shipping_methods">Shipping methods</a></td></tr><tr><td><a href="external-resources/external-payment-gateways">external-payment-gateways</a></td><td><a href="https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/orders">Orders</a></td></tr><tr><td><a href="external-resources/external-promotions">external-promotions</a></td><td><a href="https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/orders">Orders</a></td></tr><tr><td><a href="external-resources/external-tax-calculators">external-tax-calculators</a></td><td><a href="https://app.gitbook.com/s/RWJeylueWkzLadK710XZ/orders">Orders</a></td></tr></tbody></table>

The notifications data must be specified inside the `messages` node of the `data` key of the [response](#response-format), and passed as an array of objects each one containing at least least the `name` and the `body` attributes (pass the `flash` flag if you want mark the notification as temporary):

<table><thead><tr><th>Key</th><th>Type<select><option value="FFPMylDlGjZ3" label="Boolean" color="blue"></option><option value="p5pyDKHChZPn" label="Integer" color="blue"></option><option value="cLY5AewOsUef" label="Float" color="blue"></option><option value="HIvj0GlLwMl3" label="String" color="blue"></option><option value="uriZ4FxWamVK" label="Array" color="blue"></option><option value="bFLjmXlxDR1F" label="Object" color="blue"></option></select></th><th data-type="checkbox">Required</th><th>Description</th></tr></thead><tbody><tr><td><strong><code>name</code></strong></td><td><span data-option="HIvj0GlLwMl3">String</span></td><td>true</td><td>The internal name of the notification.</td></tr><tr><td><strong><code>body</code></strong></td><td><span data-option="bFLjmXlxDR1F">Object</span></td><td>true</td><td>All the information to be notified.</td></tr><tr><td><strong><code>flash</code></strong></td><td><span data-option="FFPMylDlGjZ3">Boolean</span></td><td>false</td><td>Set it to <code>true</code> to mark the notification as temporary (default is <code>false</code>).</td></tr></tbody></table>

{% tabs %}
{% tab title="Success" %}

<pre class="language-json"><code class="lang-json">{
  "success": true,
  "data": {
    ...
<strong>    "messages": [
</strong>      { 
        "name": "free_item",
        "body": { "sku_code": "AAA" },
<strong>        "flash": true 
</strong>      },
      { 
        "name": "fidelity_score",
        "body": { "score": 10000 }
      }
    ],
    "metadata": { ... }
  }
}
</code></pre>

{% endtab %}

{% tab title="Error" %}

<pre class="language-json"><code class="lang-json">{
  "success": false,
  ...
  "error": {
    "code": "YOUR-ERROR-CODE",
    "message": "Your error message"
  },
  "data": {
<strong>    "messages": [
</strong>      { 
        "name": "warning",
        "body": { "message": "Your error message" }
      }
    ]
  }
}
</code></pre>

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
You can add notifications on your response payload whether if it's succeeded or not, just remember to specify the `messages` array within the `data` key.
{% endhint %}

## Request headers

Any request sent to an external endpoint is enriched with the following headers:

<table><thead><tr><th width="337">Header</th><th>Description</th></tr></thead><tbody><tr><td><strong><code>User-Agent</code></strong></td><td>The type of external request, in the format <code>CommerceLayer {{ClassName}}</code> (e.g. <code>CommerceLayer ExternalGateway</code>).</td></tr><tr><td><strong><code>X-CommerceLayer-Signature</code></strong></td><td>The encrypted signature you need to <a href="callbacks-security">verify the callback authenticity</a>.</td></tr><tr><td><strong><code>X-CommerceLayer-TraceId</code></strong></td><td>The ID of the API request that triggered the call to external service (i.e. the <code>trace_id</code> exposed in the <code>meta</code> object of the response to that API request — useful for debugging purposes, and more).</td></tr><tr><td><strong><code>X-CommerceLayer-Topic</code></strong></td><td>The topic of the event that triggered the call to the <a href="real-time-webhooks">webhook</a> callback URL (e.g. <code>orders.place</code> — present only in that specific case). </td></tr></tbody></table>

Additionally (e.g. if you need to trace the calls to your external endpoints on your APM) you can pass the following optional [Trace Context](https://www.w3.org/TR/trace-context/) headers:

<table><thead><tr><th width="237">Header</th><th>Description</th></tr></thead><tbody><tr><td><strong><code>traceparent</code></strong></td><td>Uniquely identifies the request in a tracing system.</td></tr><tr><td><strong><code>tracestate</code></strong></td><td>Extends <code>traceparent</code> with platform-specific span or trace IDs, providing additional vendor-specific trace identification information across different distributed tracing systems.</td></tr></tbody></table>
