Create payment adapter
You can create your own adapter to any payment service provider or ERP system. A payment adapter is a public web service that you host.
- Your payment adapter will handle all communication with the PSP API.
- Everything that is needed to be used or shown on the checkout page is updated on the order.
- Payment state and all transactions are logged to Payment API.
Norce checkout handles part payments so you can for instance add gift cards as part payments and then complete the payment with a checkout payment for the remainder of the total. This makes some processes a bit more complex and the callback functions are there to handle synchronization between payments when needed.
Adapter id
Each adapter has a unique id that is used for payments and configurations. This contains psp name, psp api name with adapter suffix separated by underscore: psp_api_adapter. So Klarna Checkout adapter will use "klarna_checkout_adapter" as id.
Configuration template for your adapter
You need to register your adapter in Norce configuration service to set the configuration parameters needed to use your adapter. These can be the PSP credentials and settings that affects the behavior of the payment adapter.
Creating a payment
When there is no payment on the order a payment needs to be created. You will expose a POST endpoint for an order and add a payment to that order. Usually no other parameters are needed since the order contains all information necessary to create a payment.
POST https://payment-adapter/orders/{order_id}/payments
A checkout payment will return a html snippet that can be rendered in the frontend. A redirect payment will set the state of the payment to "processing" and return a redirectUrl that the frontend can use to redirect the customer to.
Implementation
In the create payment endpoint you start by getting the order from Order API.
GET https://order-api/checkout/orders/{order_id}
First check if a payment in intent state already exist on this order for this adapter id and throw an exception telling that this order already has an active payment for this adapter and use update instead.
Then create a payment for this payment intent to get a paymentId. You cannot add callbacks directly since you need the paymentId first.
POST https://payment/api/v0/payments
{
"adapterId": adapterId,
"name": adapterName,
"merchant": merchantId,
"channel": channelId,
"currency": order.currency,
"type": "checkout",
"orderId": orderId,
"amount": order.total.includingVat,
"state": "intent"
}
Then you need to get the configuration for your adapter.
GET https://configuration-api/merchants/{merchant_id}/channels/{channel_id}/configurations/{payment_adapter_id}
This call will return the parameters set by the merchant and channel for your adapter.
No configuration found
You should return a 400 BAD REQUEST with message "Configuration is missing for this channel."
You now have all information needed to make your call to create a new payment in the PSP API.
Map the Norce order and configuration to the PSP payment and call the PSP to create the payment.
The result of this call needs to be logged to Payment API. First update the payment with the PSP reference and add the callbacks you need.
PUT https://payment/api/v0/payments/{payment_id}
{
"adapterId": adapterId,
"name": adapterName,
"merchant": merchantId,
"channel": channelId,
"currency": order.currency,
"type": "checkout",
"orderId": orderId,
"amount": order.total.includingVat,
"state": "intent",
"reference": pspReference,
"callbacks": {
"amountChanged": adapterUrl + '/v0/orders/' + orderId + '/amount-changed'
}
}
Add a payment transaction for this payment that logs the result of this transaction.
POST https://payment/api/v0/payments/{payment_id}/transactions
{
"event": "open",
"pspEvent": "create",
"amount": order.total.includingVat,
"isSuccess": true,
"pspStatus": "created",
"requestJson": requestJson,
"responseJson": responseJson
}
This log will be available for the merchant to see all transactions made for a payment. If something fails, they should be able to contact the PSP support directly with the information given in the errorDetail.
Return a model with information from the PSP that is needed to implement the payment in a frontend, like a redirectUrl for redirect payments or a htmlSnippet for checkout payments.
Failed payment
If the call to the PSP was unsuccessful, the isSuccess should be set to false and errorDetail should be set to a fault description that will be displayed in Norce admin. If the PSP requires you to create a new reference then this payment state should be set to failed so a new payment needs to be created. You should return a 400 BAD REQUEST with the errorDetail.
Get payment
The get payment endpoint is used to get the current state of a payment. This endpoint should return information from the PSP that is needed by the frontend, usually the same information that is returned in the create payment endpoint.
GET https://payment-adapter/orders/{order_id}/payments/{payment_id}
Update payment
The update payment will update a payment at the PSP when something has changed on the order.
Implementation
In the update payment endpoint you start by getting the order from Order API.
GET https://order-api/checkout/orders/{order_id}
Then you need to get the configuration for your adapter as in create payment.
You now have all information needed to make your call to update the payment in the PSP API.
Map the Norce order and configuration to the PSP payment and call the PSP to update the payment.
The result of this call needs to be logged to Payment API as in Create payment.
Handle payment amount changed
When the order amount changes or a part payment with another payment method affects the order, then the amountChanged callback will be called and this is the endpoint that deals with that callback.
POST https://payment-adapter/orders/{order_id}/payments/{payment_id}/amount-changed
{
"amount": 249.9
}
Implementation is the same as in Update payment but you use the amount in the amountChanged callback body instead.
Callbacks from payment provider
All callbacks and redirects from a payment provider should go through an endpoint of the PSP adapter to log the callback to the Payment API and handle state change of the payment.
Cancel payment
When a user cancels a payment in a redirect or checkout payment you should go through a cancel endpoint where you log the event. If the PSP don't allow for a payment to try again then change state to failed. Otherwise if payment is in processing stat, then revert it to intent state.
GET https://payment-adapter/callback/cancel : 301 Redirect to checkout page
Validate payment
For a checkout or redirect payment where the PSP has a validate callback you do the payment validation here. Otherwise you need to validate on each create and update.
GET/PUT/POST https://payment-adapter/callback/validation
PSP determines how this endpoint is designed since the call comes from them.
Confirm payment
Adding callbacks
You add callbacks that your adapter needs to react upon. All adapters need to implement amountChanged callback since that handles when the amount the payment is intended to cover changes. Process, abort and confirm callbacks are mainly implemented by gift cards to make and cancel reservations of gift cards and commit the value on confirm.
Payment callbacks
Callback | Description |
---|---|
process | When the user clicks "Complete checkout" the order starts to validate all payments. This is a final validation step where you may reserve funds. Some payment methods like checkout payments starts this process with a callback from the PSP to the payment adapter instead. In that case the process step is handled between the PSP and adapter and the adapter is responsible for changing the state of the order to processing. |
abort | If any process callback fails, then an abort call is made to each of the active payments so reservations can be cancelled. If no reservation has been made during process callback, then don't add this callback. |
confirm | When the main payment method completes all other part payments gets a complete call. A main payment method starts this process from the PSP and is responsible to |
amountChanged | When the cart total or another payment amount changes. This must be implemented by all adapters. |
After payment callbacks
The after payment callbacks determine what capabilities this adapter has after the purchase is done. Add callbacks for capture, cancel and refund to tell Norce order management that this payment can be captured, cancelled or refunded.
Callback | Description |
---|---|
cancel | If the payment can be cancelled after it has been confirmed but before it has been captured, then add this callback. This will allow Norce admin to handle manual cancelling of payment reservations. |
capture | When the order state is changed to delivered. For payments where amount is reserved at complete and captured or settled upon delivery. If that is not the case, then don't add this callback. |
refund | When a captured payment needs to be refunded. If not possible to do refunds, then don't add this callback. |
PUT https://payment/api/v0/payments/{payment_id}
{
...
"callbacks": {
"process": adapterUrl + '/v0/orders/' + orderId + '/payments/' + paymentId + '/process',
"abort": adapterUrl + '/v0/orders/' + orderId + '/payments/' + paymentId + '/abort',
"confirm": adapterUrl + '/v0/orders/' + orderId + '/payments/' + paymentId + '/confirm',
"amountChanged": adapterUrl + '/v0/orders/' + orderId + '/payments/' + paymentId + '/amount-changed',
"capture": adapterUrl + '/v0/orders/' + orderId + '/payments/' + paymentId + '/capture',
"cancel": adapterUrl + '/v0/orders/' + orderId + '/payments/' + paymentId + '/cancel',
"refund": adapterUrl + '/v0/orders/' + orderId + '/payments/' + paymentId + '/refund'
}
}
When payment and order is updated you can return a response with information needed to complete the payment.