Token Refunds
In addition to the Token Wallet functionality, Checkout allows for the unique token to be used for refund processing via API. One such use case for this functionality is in back-office systems where refunds/compensation payments which do not always relate to an initial purchase can then be processed.
This method can only be used for Refunds. If you wish to make Merchant Initiated Transactions, you should use the Recurring Transaction API instead.
Authentication
As the payment instrument, the token, is being passed in by the integrator the authentication method required is the same as used when initiating a new payment. See Authentication for the full breakdown of the request and response. It is important to remember that this authentication method means that certain fields in the authentication request (e.g. amount
, invoiceId
etc.) must match in the below request, otherwise the request will be rejected.
Token Refund Request
Method | POST |
tokenPayment | |||||
---|---|---|---|---|---|
Field Name | State | Data Type | Description | ||
transactionType | Optional | String | Type of transaction.
| ||
invoiceId | Mandatory | String | Order/invoice/transaction/basket number generated by the host website, as passed in the request. | ||
accountId | Optional | String | Unique reference for the store processing the transaction. | ||
description | Optional | String | Message from host website to consumer. | ||
merchantCustomData | Optional | String Max 1024 bytes | Free text field for integrated system to pass custom data that will be stored against the transaction. This data will be returned in the result and available via the Transaction Management functions. | ||
terminalId | Mandatory | String | Terminal ID used when authorising the transaction. | ||
amount | Mandatory | Decimal | Total amount of the original order/authorisation including decimal places where applicable. | ||
ipAddress | Optional | String | IP address of the computer on which the transaction is being performed. | ||
currency | Mandatory | String | Currency of the transaction.
| ||
phone | Optional | String | Consumer’s contact phone number. | ||
Optional | String Max 256 Char. | Email address provided by consumer as main contact address. |
Token Refund Request > Card
tokenPayment.card | |||
---|---|---|---|
Field Name | State | Data Type | Description |
accountNumber | Optional | String | Masked PAN showing the last four digits of the card – for example “************9909”. |
cardTokenId | Mandatory | String | The Token for the card, returned in the previous integrated transaction. |
csc | Optional | Encrypted String | If required by the merchant, the token transaction can also verify the card security code (CSC). If this validation is required, the CSC should be encrypted with RSA-OAEP (sha256 is used as a hash function) algorithm using DNA Public Key (key length 4096 bits) with an OAuth token used as the label parameter and base64 encoded. For more details on how to complete this encryption please see Encrypting the Card Security Code (CSC). |
cardType | Optional | String | The Optomany card scheme ID for the card whose token is presented. |
expirationMonth | Optional | String | The month, in digits, in which the card expires. For example, a card expiring in December would be “12”. |
expirationYear | Optional | String | The year, in digits, in which the card expires. For example, a card expiring in 2022 would be “22”. |
The CSC must never be stored beyond the time taken to capture, encrypt and send the request. For more detail, please see Encrypting the Card Security Code (CSC)
Token Refund Response
Transaction Settlement | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
Field Name | Data Type | Description | ||||||||
id | String | Unique transaction ID. This ID should be stored as it is required for later transaction actions. | ||||||||
description | String | Descriptive text for the transaction. | ||||||||
phone | String | Phone number passed in the request. | ||||||||
amount | Decimal | Total amount of the order including decimal places where applicable. ‘Whole’ amounts (e.g. “1”) on a GBP account represents £1.00. | ||||||||
currency | String | Currency of the transaction.
| ||||||||
invoiceId | String | Order/invoice/transaction/basket number generated by the host website, as passed in the request. | ||||||||
accountId | String | Unique reference for the store processing the transaction, as passed in the request. | ||||||||
authDateTimeUTC | String | Date and time of when the transaction was authorised with the acquirer. | ||||||||
responseCode | String | Returned by the acquirer detailing the result of the transaction. A full list of Response Codes can be found here. | ||||||||
success | Boolean | Confirms whether the transaction has been successful.
| ||||||||
settled | Boolean | Confirms whether the transaction has been submitted for overnight settlement.
| ||||||||
message | String | Message confirming the processing result of the transaction request. | ||||||||
authCode | String | Authorisation code issued for the transaction. | ||||||||
cscResult | String | Confirms the result of the Card Security Code (CSC) validation check.
| ||||||||
payerAuthenticationResult | String | Result of the Payer Authentication process provided in the following format “enrolment result/authentication result”. As the Token Payment is not processed using Payer Authentication the result will always be the below.
| ||||||||
optomanyTerminalId | String | Optomany Terminal ID used when authorising the transaction. | ||||||||
cardExpiryDate | String | Expiry date for the card used in the transaction. Provided in the “MM/YY” format. | ||||||||
cardPanStarred | String | Starred PAN for the card used in the transaction - for example ************9909. | ||||||||
cardTokenId | String | Optomany Token ID for the card presented. | ||||||||
cardSchemeId | Integer | Optomany Card Scheme ID for the card used in the transaction. | ||||||||
cardSchemeName | String | Name of the Card scheme for the card used in the transaction. | ||||||||
cardIssuingCountry | String | Country where the card was issued. This information will only be returned when this can be determined. This information is subject to change and as such we recommend only using this data as a guide. |
Encrypting the Card Security Code
The Card Security Code (CSC) should be encrypted with RSA-OAEP (sha256 is used as a hash function) algorithm using DNA Public Key (key length 4096 bits) with the OAuth token from the authentication process used as the label parameter and base64 encoded.
OAEP is parameterised by a hash function that is used as a random oracle. Encryption and decryption of a given message must use the same hash function (sha256.New() is used as a hash function).
The random parameter is used as a source of entropy to ensure that encrypting the same message twice does not result in the same ciphertext.
The label parameter may contain arbitrary data that will not be encrypted, but which gives important context to the message. For example, if a given public key is used to decrypt two types of messages then distinct label values could be used to ensure that a ciphertext for one purpose cannot be used for another by an attacker.
For the processing of test transactions the below RSA key should be used.
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1NxKkkEAfAGw9Lo1/26oE9d2REF5fz2TC1WobV7WgDnuAhBsmyMy/TnQRVmyC8u1vy8Sxvspn9jY2YGe6/n249FK1RAzafV7mXOrMF1yqfXBMZhBwd+CHIXhETb/Pl7pjVPs8Fsk+uq/ZPB8WUVK6sNSzbAYG6TC4/DEFADxFHAxXOq9QaTO/QTX9JqzfP13XqOQqW5DmpWG52Qn69pV9fgI5eSLc25DgOjjw8fQvDnbM2MQNYr/YhjrDUZN1jrWWMrjqAN9V9dg9dE+YAmyq9boexJ/WC027MgkkVIMDO252U3qg2mpvbtdcs9Lfg0tL8z2nRUBc/cS3HRXcu4nP7E9pzqsLeWpC0BJw/kAwL79yZTOlTqdhDGo1WWRL3km9EFfEqugf3yguSR+mOODPyruD7r8OI40GLRqlorgiwF2srUZWhx+UObirtTIb4fLqrRl5wfi+mHgHt7Q0qOTX/qAXiWr3fueiNPs8AsmCoIq6OGIGCyFgjSNL2SK5RrtV5fB561Lu4FxurIH3KQq5EryGSjPlL2vl6fJFsFyEw8Cx3isuMVVmGx7DSVznXQDIhcU+akvQkjNHgtj+Ac0V5+h/uWhbF8DmnHyjhejs7vBVZvFl1hcCHVDQCmi/H2BPJ39Z+2rz4ljyYjkM74IPWF6CwJumST7ITF03zDh3akCAwEAAQ==
-----END PUBLIC KEY-----
For live integrations, the live RSA Key will be issued by the Implementations team following the completion of Integration Approval.
Examples
Tokenisation Request and Response Examples
- Request
- Response
{
"transactionType":"SALE",
"invoiceId": "TESTSDTOKEN2",
"accountId": "1724",
"description": "Order description",
"merchantCustomData": "Custom data",
"terminalId": "a398d836-aeae-44e8-90b3-6726ecbdb604",
"amount": 5,
"ipAddress": "202.31.57.4",
"currency": "GBP",
"phone": "45373945",
"email": "test@email.com",
"card": {
"accountNumber":"************9909",
"cardTokenId": "XZXIx6WNM+vyvTFBOlGObOZazHurxVN6Sgjxq+CYhVcfMQ==",
"csc": "XqO8gM2GZDvEMjYcLnl/b3uMsz2TV6lIr00Ve0KIWkzqfptho4mWSe+s272+GD2FS5eZ5k6dNBr17FDwYm/UFG+iHml4bCN9KDld7SfSAnBHYXEymOItU6Md0UR8NpNHOHrEaDSQrua+jIjQ2RmwrQwGEzPrILD8Qb+EbTERDuS86CzlXI43EMiKn+iFW6Zt1YYtuQF3zh4qFXUFWAccudKAohhjaVl56nK/kW9dZO54xR6JatUpoCaHD1OWqw3aVGReFw7HdCgLsRfYflIvJGy6mQ2/Glt0JnNjW4BMCkJ1fwgT8Ge0UxN7dfmvnEDLqd3a0r2vcxSgxc1mnIzXbTAY7DTiiR2WraI9Xwyk5rOf2rg4SgqCmExrwrakHw4B1GNY9QFqDayRELVEgdU1nno5q27R2PnfDXG2uzIti24KtdfDJmG3gGzdWt0VHEgzHFPui4LojMeVKtAAfi6Ouy1UxrJo6YbKiJXM3mfRCDM4jD5T2rApMmD+9RkdRdEwpkwego2LpbrqBkW5Sz0N6e/g2qYmslgrJdN5qSJ/XHzKsCx51KbGoo7fMtskgDMuy3j+OoY/GBjL1Bi4SyUZhqe9jGL0I76g6NBqp4DwHhhrbZs4AsId9n25bAOgH3+U+uzelMeK5ppEINa+v3407WnlE6UUzPgq0EoApDsPPPo=",
"cardType": "8",
"expirationMonth": "12",
"expirationYear": "22"
}
}
{
"id": "9ac0a0d5-b628-41f6-aab6-94cac8dcb603",
"accountId": "1724",
"amount": 5,
"currency": "GBP",
"description": "Order description",
"invoiceId": "TESTSDTOKEN2",
"phone": "45373945",
"reference": "8653/1379/24022021102723000",
"success": true,
"settled": true,
"payerAuthenticationResult": "-/-",
"responseCode": "00",
"authDateTimeUTC": "2021-02-24T10:27:23.68174427Z",
"message": "Authorised and settled",
"authCode": "123ABC",
"cscResult": "Matched",
"optomanyTerminalId": "31292612",
"cardExpiryDate": "12/22",
"cardPanStarred": "************9909",
"cardTokenId": "XZXIx6WNM+vyvTFBOlGObOZazHurxVN6Sgjxq+CYhVcfMQ==",
"cardSchemeId": 8,
"cardSchemeName": "MasterCard",
"cardIssuingCountry": "Brazil"
}
CSC Encryption Example
You can view and execute this code here
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"log"
)
func main() {
//<<<<<<The first parameter in the "encrypt" function below is the CSC to encrypt,>>>>>
//<<<<<<and the third parameter is the authentication token.>>>>>>>
ciperText, err := encrypt("321", getIdRsaPub(), "3QA-wH4Zf5YfkF_g44Pyf$1ufZ$BAOG1!EQ0PYTD-nEo!OZJjqtV7dRnjZpxDmAk")
if err != nil {
log.Printf("ERROR: fail encrypt - %s", err.Error())
}
log.Printf("INFO: ciper text - %s", ciperText)
}
func encrypt(payload string, key *rsa.PublicKey, token string) (string, error) {
// params
msg := []byte(payload)
rnd := rand.Reader
hash := sha256.New()
// encrypt with OAEP
ciperText, err := rsa.EncryptOAEP(hash, rnd, key, msg, []byte(token))
if err != nil {
log.Printf("ERROR: fail to encrypt, %s", err.Error())
return "", err
}
return base64.StdEncoding.EncodeToString(ciperText), nil
}
func getIdRsaPub() *rsa.PublicKey {
keyData := `-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1NxKkkEAfAGw9Lo1/26oE9d2REF5fz2TC1WobV7WgDnuAhBsmyMy/TnQRVmyC8u1vy8Sxvspn9jY2YGe6/n249FK1RAzafV7mXOrMF1yqfXBMZhBwd+CHIXhETb/Pl7pjVPs8Fsk+uq/ZPB8WUVK6sNSzbAYG6TC4/DEFADxFHAxXOq9QaTO/QTX9JqzfP13XqOQqW5DmpWG52Qn69pV9fgI5eSLc25DgOjjw8fQvDnbM2MQNYr/YhjrDUZN1jrWWMrjqAN9V9dg9dE+YAmyq9boexJ/WC027MgkkVIMDO252U3qg2mpvbtdcs9Lfg0tL8z2nRUBc/cS3HRXcu4nP7E9pzqsLeWpC0BJw/kAwL79yZTOlTqdhDGo1WWRL3km9EFfEqugf3yguSR+mOODPyruD7r8OI40GLRqlorgiwF2srUZWhx+UObirtTIb4fLqrRl5wfi+mHgHt7Q0qOTX/qAXiWr3fueiNPs8AsmCoIq6OGIGCyFgjSNL2SK5RrtV5fB561Lu4FxurIH3KQq5EryGSjPlL2vl6fJFsFyEw8Cx3isuMVVmGx7DSVznXQDIhcU+akvQkjNHgtj+Ac0V5+h/uWhbF8DmnHyjhejs7vBVZvFl1hcCHVDQCmi/H2BPJ39Z+2rz4ljyYjkM74IPWF6CwJumST7ITF03zDh3akCAwEAAQ==
-----END PUBLIC KEY-----`
keyBlock, _ := pem.Decode([]byte(keyData))
if keyBlock == nil {
log.Printf("ERROR: fail get idrsapub, invalid key")
return nil
}
publicKey, err := x509.ParsePKIXPublicKey(keyBlock.Bytes)
if err != nil {
log.Printf("ERROR: fail get idrsapub, %s", err.Error())
return nil
}
switch publicKey := publicKey.(type) {
case *rsa.PublicKey:
return publicKey
default:
return nil
}
}
This code is provided as an example only, please ensure you understand any code you include in your project as you will be responsible for it.