# External payment gateways

Commerce Layer is [integrated](https://docs.commercelayer.io/developers/v/how-tos/payments) with some of the most popular payment gateways — **Adyen**, **Axerve**, **Braintree**, **Checkout.com**, **Klarna**, **Paypal**, and **Stripe**. They are all compliant with the PSD2 European regulation so that you can implement a payment flow that supports SCA and 3DS2.

Adding new payment gateways to our core is already provided for in our roadmap. Anyway, you already have the complete flexibility to connect to whichever payment service provider you may need. To do that, just create an external payment gateway and define your custom endpoint(s) responding to the following actions:

1. [Authorization](#authorization) — to authorize a payment source
2. [Capture](#capture) — to capture an authorization
3. [Void](#void) — to void an authorization
4. [Refund](#refund) — to refund a capture, either totally or partially
5. [Customer token](#customer-token) — to create a customer payment token

Your external endpoint will be responsible for the actual integration with the payment gateway. The payment source associated with the order must be an [external payment](https://docs.commercelayer.io/developers/v/api-reference/external_payments).

{% hint style="info" %}
External gateways process payments **synchronously** by default. If you need your gateway to behave differently, check the [asynchronous payments section](#asynchronous-payments).
{% 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** — which depends on the kind of gateway's transaction — some **relationships** are also included to avoid useless API roundtrips:

* `order`
* `order.market`
* `order.line_items`
* `order.line_items.item`
* `order.shipping_address`
* `order.billing_address`
* `order.customer`
* `order.order_subscriptions`

```json
{
  "data": {
    ...
  },
  "included": [
    {
      "id": "wBXVhKzrnq",
      "type": "orders",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "DvlGRmhdgX",
      "type": "markets",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "kdPgtRXOKL",
      "type": "line_items",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "XGZwpOSrWL",
      "type": "skus",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "BgnguJvXmb",
      "type": "addresses",
      "links": { ... },
      "attributes": { ... },
      "relationships": { ... },
      "meta": { ... }
    },
    {
      "id": "AdcreKwJnd",
      "type": "order_subscriptions",
      "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 the specific transaction's relationships within the `external_includes` attribute of the external payment gateway 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. A failed transaction (of the specific type) is created by using the related response error message and the circuit breaker internal counter (if closed) is incremented.
{% endhint %}

### Authorization

When you place an order, Commerce Layer triggers a `POST` request to the endpoint that you specified in the `authorize_url` field and creates an authorization.

#### Example

{% tabs %}
{% tab title="Payload" %}
The request payload contains the external payment resource and includes the [above-mentioned](#request) relationships:

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

{% endtab %}

{% tab title="Response" %}
The successful response must be a JSON object, returning at least a transaction token (e.g. the one provided by the payment gateway) and the total amount that has been authorized. 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>    "transaction_token": "your-external-transaction-token",
</strong><strong>    "amount_cents": 12900,
</strong>    "messages": [ ... ],
    "metadata": {
      "foo": "bar"
    }
  }
}
</code></pre>

{% 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 associated order.
{% endhint %}
{% endtab %}

{% tab title="Error" %}
On error, you must respond with an HTTP code >= `400`. The response body must be a JSON object containing a transaction token (e.g. the one provided by the payment gateway) and the authorization amount, along with any other relevant error code and message:

```json
{
  "success": false,
  "data": {
    "transaction_token": "your-external-transaction-token",
    "amount_cents": 12900
  },
  "error": {
    "code": "YOUR-ERROR-CODE",
    "message": "Your error message"
  }
}
```

{% endtab %}
{% endtabs %}

### Capture

When you try to capture an authorization, Commerce Layer triggers a `POST` request to the endpoint that you specified in the `capture_url` field and creates a capture.

#### Example

{% tabs %}
{% tab title="Payload" %}
The request payload contains the authorization resource and includes the [above-mentioned](#request) relationships:

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

{% endtab %}

{% tab title="Response" %}
The successful response must be a JSON object, returning at least a transaction token (e.g. the one provided by the payment gateway) and the total amount that has been captured. 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>    "transaction_token": "your-external-transaction-token",
</strong><strong>    "amount_cents": 12900,
</strong>    "messages" : [ ... ],
    "metadata": {
      "foo": "bar"
    }
  }
}
</code></pre>

{% 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 associated order.
{% endhint %}
{% endtab %}

{% tab title="Error" %}
On error, you must respond with an HTTP code >= `400`. The response must be a JSON object containing a transaction token (e.g. the one provided by the payment gateway) and the capture amount, along with any other relevant error code and message:

```json
{
  "success": false,
  "data": {
    "transaction_token": "your-external-transaction-token",
    "amount_cents": 12900
  },
  "error": {
    "code": "YOUR-ERROR-CODE",
    "message": "Your error message"
  }
}
```

{% endtab %}
{% endtabs %}

### Void

When you try to void an authorization, Commerce Layer triggers a `POST` request to the endpoint that you specified in the `void_url` field and creates a void.

#### Example

{% tabs %}
{% tab title="Payload" %}
The request payload contains the authorization resource and includes the [above-mentioned](#request) relationships:

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

{% endtab %}

{% tab title="Response" %}
The successful response must be a JSON object, returning at least a transaction token (e.g. the one provided by the payment gateway) and the total amount that has been voided. 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>    "transaction_token": "your-external-transaction-token",
</strong><strong>    "amount_cents": 12900,
</strong>    "messages": [ ... ],
    "metadata": {
      "foo": "bar"
    }
  }
}
</code></pre>

{% 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 associated order.
{% endhint %}
{% endtab %}

{% tab title="Error" %}
On error, you must respond with an HTTP code >= `400`. The response must be a JSON object containing a transaction token (e.g. the one provided by the payment gateway) and the void amount, along with any other relevant error code and message:

```json
{
  "success": false,
  "data": {
    "transaction_token": "your-external-transaction-token",
    "amount_cents": 12900
  },
  "error": {
    "code": "YOUR-ERROR-CODE",
    "message": "Your error message"
  }
}
```

{% endtab %}
{% endtabs %}

### Refund

When you try to void a capture, Commerce Layer triggers a `POST` request to the endpoint that you specified in the `refund_url` field and creates a refund.

#### Example

{% tabs %}
{% tab title="Payload" %}
The request payload contains the capture resource and includes the [above-mentioned](#request) relationships:

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

{% endtab %}

{% tab title="Response" %}
The successful response must be a JSON object, returning at least a transaction token (e.g. the one provided by the payment gateway) and the amount that has been refunded. 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>    "transaction_token": "your-external-transaction-token",
</strong><strong>    "amount_cents": 9900,
</strong>    "messages": [ ... ],
    "metadata": {
      "foo": "bar"
    }
  }
}
</code></pre>

{% 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 associated order.
{% endhint %}
{% endtab %}

{% tab title="Error" %}
On error, you must respond with an HTTP code >= `400`. The response must be a JSON object containing a transaction token (e.g. the one provided by the payment gateway) and the refund amount, along with any other relevant error code and message:

```json
{
  "success": false,
  "data": {
    "transaction_token": "your-external-transaction-token",
    "amount_cents": 9900
  },
  "error": {
    "code": "YOUR-ERROR-CODE",
    "message": "Your error message"
  }
}
```

{% endtab %}
{% endtabs %}

### Customer token

When you try to store a payment token for a customer, Commerce Layer triggers a `POST` request to the endpoint that you specified in the `token_url` field and creates a customer payment source for the specified payment.

#### Example

{% tabs %}
{% tab title="Payload" %}
The request payload contains the payment source resource and includes the [above-mentioned](#request) relationships:

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

{% endtab %}

{% tab title="Response" %}
The successful response must be a JSON object, returning an optional `customer_token` (if missing the `customer.email` is used) and the `payment_source_token` that represents the saved payment for the customer:

<pre class="language-json"><code class="lang-json">{
  "success": true,
  "data": {
<strong>    "customer_token": "your-external-customer-token",
</strong><strong>    "payment_source_token": "your-external-payment-source-token"
</strong>    }
  }
}
</code></pre>

{% endtab %}

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

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

{% endtab %}
{% endtabs %}

### Asynchronous payments

It might be the case you don't want your gateway to process payments immediately. That's why Commerce Layer provides the option to [mark](#action-id) your external gateway response as **asynchronous** and [exposes](#webhook-endpoint) a `webhook_endpoint_url` you can call once the payment status changes.

{% hint style="info" %}
The `token_url` doesn't support asynchronous execution.
{% endhint %}

#### Action ID

A payment is marked as asynchronous when the following conditions on the response to any of the external payment gateway transactions are met:

* HTTP code is `202`
* It contains the `action_id` key, which *uniquely* identifies the related transaction

{% hint style="info" %}
`action_id` uniqueness is mandatory for the [webhook](#webhook-endpoint) to detect the transaction later.
{% endhint %}

In this case, the external payment gateway creates the transaction setting the `succeeded` attribute to `false`, but considering it as pending. This way, the order can be placed without errors, but the order payment status doesn't change yet (even if the order is not editable anymore).

#### Example

{% tabs %}
{% tab title="Payload" %}
The payload requested by the related transaction, as explained in the [authorization](#authorization), [capture](#capture), [void](#void), and [refund](#refund) sections.
{% endtab %}

{% tab title="Response" %}
The successful response must be a JSON object, returning a transaction token (e.g. the one provided by the payment gateway), the amount involved, and the unique identifier of the transaction. If needed, you can add some metadata that will be copied into the related transaction resource that is being created:

```json
{
  "success": true,
  "data": {
    "transaction_token": "your-external-transaction-token",
    "amount_cents": 12900,
    "action_id": "your-action-id",
    "metadata": {
      "foo": "bar"
    }
  }
}
```

{% endtab %}

{% tab title="Error" %}
On error, you must respond with an HTTP code >= `400`. The response must be a JSON object containing a transaction token (e.g. the one provided by the payment gateway) and the amount involved in the transaction, along with any other relevant error code and messagee:

```json
{
  "success": false,
  "data": {
    "transaction_token": "your-external-transaction-token",
    "amount_cents": 12900
  },
  "error": {
    "code": "YOUR-ERROR-CODE",
    "message": "Your error message"
  }
}
```

{% endtab %}
{% endtabs %}

#### Webhook endpoint

To notify the payment has changed its status, the external gateway exposes a `webhook_endpoint_url` you can call accordingly once the related payment transaction gets an update, as long as you follow these requirements:

* It accepts only POST requests.
* You must include an **X-CommerceLayer-Signature** header, which contains the [HMAC](https://en.wikipedia.org/wiki/HMAC) of the request payload signed with a **SHA256** algorithm and the same [shared secret](#security) already exposed by the external payment gateway.
* The request body must have the same structure as the response — a JSON object with the transaction's attributes you need to update — and include the `action_id` previously used.

The external payment gateway will use this data to fetch the pending transaction and update the attributes with the new values. On successful update, the transaction `succeeded` attribute is set to `true` and the order is updated to the right status — `authorized`, `paid`, `voided`, or `refunded`. In case of error, the order status remains as it is.

{% hint style="info" %}
The `webhook_endpoint_url` is generated upon the external gateway creation and you can find it in the gateway's details page on the admin dashboard.
{% endhint %}

#### Updatable attributes

Only a subset of attributes is allowed for an update, assuming the main ones have already been set by [the first async response](#action-id) (e.g. `amount_cents` and `transaction_token` cannot be updated). The updatable transaction fields are:

* `message`
* `error_code`
* `error_detail`
* `avs_code`
* `avs_message`
* `cvv_code`
* `cvv_message`
* `fraud_review`

### Security

When you create a new external payment gateway, a **shared secret** is generated. 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 %}
