External Payment Plugin

Last updated

External payment plugin allows you to integrate Payment Service Providers of your choice that are not supported by Centra. It is intended to be used along with Checkout API, however requests finalizing payments should be handled server-side as payload signature using shared secret is required.

Setup#

External payment plugin settings look like this:

img.png

To set up External Payment Plugin you need to provide all the basic plugin information like Name, Name in Frontend, URI and:

  • Notification key - auto-generated value used to authorize authorization and capture notifications to endpoint visible under Notifications URL. Must be stored server-side and not revealed to third parties.

  • Shared secret - auto-generated value used to sign payload send to endpoints finalizing the payment when External Payment Plugin is used. Must be stored server-side and not revealed to third parties.

Flow#

The integration with Payment Service Provider, order creation and management must be done outside of Centra. Results of payment authorization and capture from redirects and push notifications should be forwarded to Centra to proper endpoints.

  • Customer goes to checkout. Centra API gets a GET /selection

  • external-payment method is found and can be selected for checkout

  • POST /payment request is made with "paymentMethod": "external-payment" which on success responds with following data:

1 2 3 4 5 { "token": "abcd1234efgh12340ba6142228334aaf4", "action": "external", "selection": "4f1211119567211c441d86e19fbd7114" }

You should store the selection field value. It needs to be included in signature payload when finalizing the payment. At the same time you will most probably initiate the payment session with Payment Service you're integrating, so you should associate the selection id from Centra with payment session identifier from Payment Service.

1 2 //this will be needed to finalize the order [paymentSessionIdentifier, selectionId]

Order finalization#

  • Redirect

When user finalizes the payment in html widget and gets redirected to the success page you will send data provided by Payment Service back to your backend so that it can be signed and forwarded to Centra's payment-result endpoint. At this point you should use the value pair stored before to map payment result you've obtained from Payment Service to its associated selection id:

1 [paymentSessionIdentifier, selectionId]

Sign the payload and send a POST /payment-result (as shown in details below).

  • Authorisation push notification

Authorisation result will be also send to your backend by Payment Service through webhook or so-called push notification. Here you should also use value pair:

1 [paymentSessionIdentifier, selectionId]

to trace back selection id from paymentSessionIdentifier. You should forward this request to Centra push notification endpoint (details below).

There is no way to provide or update the customer address using requests finalizing the payment. Centra needs to know the customer address before. Not providing the address before will result in invalid orders with empty address.

Captures#

Captures must be handled outside of Centra within your own integration with Payment Service. Result of capture should be sent towards push notification endpoint using signed request with intent=capture.

This endpoint is intended for receiving authorization information. It can be called only once with successful authorization per order.

Request:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 { "paymentMethodFields": { "selection": "selection", "signature": "signature", "currency": "SEK", "amount": "100.00", "timestamp": 1627029828, "transactionReference": "transactionReference", "success": true, "transaction": { "key": "value" } } }
<div class="tableWrapper" markdown='1'> | Field | Type | Comment | | ----- | ---- | ------- | | `selection` | string | Selection id returned at `POST /payment` call | | `signature` | string | Base64 encoded signed payload (details below) | | `currency` | string | Currency code (ISO 4217) | | `amount` | string | Numeric string with dot as decimal separator | | `timestamp` | int | Signature unix timestamp in UTC. Must be provided in seconds. The value is validated so you need to provide the current timestamp each time you send a request. | | `transactionReference` | string | Transaction identifier from PSP| | `success` | boolean | Successful or failed result of payment authorization| | `transaction` | object | All the transaction details that were received from PSP| </div>

Signature

The signature is a base64 encoded HMAC SHA256 hash. Shared secret is configurable in External Payment Plugin settings in Centra AMS. Browser snippet using JavaScript and CryptoJS library:

1 btoa(CryptoJS.HmacSHA256(payload, secret).toString(CryptoJS.digest));

Node snippet using popular npm package crypto-js:

1 2 3 let hashedSignature = HmacSHA256(str, secret); //CryptoJS.lib.WordArray let hashedSignatureHex = hashedSignature.toString(); //hex encoded string let base64encodedSignature = Buffer.from(hashedSignatureHex).toString('base64'); //base64 encoded signature
Signature payload fields

Signature payload fields must be provided in following order, separated by colon:

  • selection id (received in POST /payment call)
  • amount
  • currency
  • timestamp
  • transactionReference
  • success

payload: selectionId:amount:currency:timestamp:transactionReference:success

Response:

On success=true it will respond with HTTP status 201 and order object. The order will be created in Centra backend. (note: only one such call per order is allowed)

On success=false Centra will store the information about failed authorization and will respond with HTTP status 412. The order is not created yet.

example error response:

1 2 3 4 5 6 7 8 9 { "token": "123412341234b11b35328200afd1234", "errors": { "paymentMethod": "failed" }, "messages": [ "Mismatched currency: USD, basket currency: SEK" ] }

Request:

1 2 3 4 5 6 7 8 9 10 11 12 13 { "selection": "selection", "signature": "signature", "currency": "SEK", "amount": "100.00", "timestamp": 1627029828, "transactionReference": "transactionReference", "success": true, "intent": "auth", "transaction": { "key": "value" } }
FieldTypeComment
selectionstringSelection id returned at POST /payment call
signaturestringBase64 encoded signed payload (details below)
currencystringCurrency code (ISO 4217)
amountstringNumeric string with dot as decimal separator, e.g. "100.00"
timestampintSignature unix timestamp in UTC
transactionReferencestringTransaction identifier from PSP
successbooleanSuccessful or failed result of payment authorization
intentstringIntent of a notification, possible values: auth/capture
transactionobjectAll the transaction details that were received from PSP

Signature

The signature is a base64 encoded HMAC SHA256 hash. Example code using JavaScript and CryptoJS library:

1 btoa(CryptoJS.HmacSHA256($payload, secret).toString(CryptoJS.digest));
Signature payload fields

Signature payload fields must be provided in following order, separated by colon:

  • selection id (received in POST /payment call)
  • amount
  • currency
  • timestamp
  • transactionReference
  • success
  • intent

payload: selectionId:amount:currency:timestamp:transactionReference:success:intent

Response:

If the push notification is accepted Centra will respond with HTTP status 200.

Example response:

1 2 3 4 { "success": true, "message": "OK" }

Status other than 200 indicates that something went wrong. Either the sent data is corrupted or other error occured like some fields missing or invalid signature. This may result in payments not visible in Centra and orders not being accepted. The message field of response object will contain the failure reason.

Example response:

1 2 3 4 { "success": false, "message": "Invalid intent: test" }

Only one successful (success=true) authorization and one successful (success=true) capture is allowed per order.

Captures and refunds:#

Captures and refunds should be handled outside of Centra. Captures and refunds triggered by Order API or AMS are forbidden for orders paid with External Payment Plugin and will result in following error:

img.png

  • Capturing shipments or trying to create refund via creating return in Order API are also not allowed for orders paid with External Payment Plugin:
1 2 3 4 5 { "status": "no", "msg": "Action not supported by external payment plugin. Please do that action in your payment provider.", "order": 123 }