External payment gateways
How to manage payments and transactions via external services
Commerce Layer is integrated 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:
Authorization — to authorize a payment source
Capture — to capture an authorization
Void — to void an authorization
Refund — to refund a capture, either totally or partially
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.
External gateways process payments synchronously by default. If you need your gateway to behave differently, check the asynchronous payments section.
Request
The request payload is a JSON:API 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
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. 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.
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
The request payload contains the external payment resource and includes the above-mentioned relationships:
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
The request payload contains the authorization resource and includes the above-mentioned relationships:
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
The request payload contains the authorization resource and includes the above-mentioned relationships:
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
The request payload contains the capture resource and includes the above-mentioned relationships:
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
The request payload contains the payment source resource and includes the above-mentioned relationships:
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 your external gateway response as asynchronous and exposes a webhook_endpoint_url
you can call once the payment status changes.
The token_url
doesn't support asynchronous execution.
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
action_id
uniqueness is mandatory for the webhook to detect the transaction later.
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
The payload requested by the related transaction, as explained in the authorization, capture, void, and refund sections.
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 of the request payload signed with a SHA256 algorithm and the same shared secret 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.
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.
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 (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.
Last updated