Description | Link |
---|---|
Home | http://reddotpayment.com/ |
Contact us | http://reddotpayment.com/contact-us/ |
Test Dashboard | http://test.reddotpayment.com/instanpanel/ |
If you don't have a sandbox account setup on Red Dot Payment (RDP), you can submit a request to generate one through their Contact Us page.
After the account is setup, you will be able to access the dashboard and see all your transactions there.
Contents:
Description | Link |
---|---|
Overview | http://reddotpayment.com/developers/?page_id=586 |
Generate signature | http://reddotpayment.com/developers/?page_id=601 |
API Request and Response | http://reddotpayment.com/developers/?page_id=620 |
Response codes | http://reddotpayment.com/developers/?page_id=629 |
Note: To use this API, you need to confirm with RDP that your sandbox account is configured to use the tokenization feature. Else, you will see the error "Your account is not setup to access RDP TOKENIZATION Feature".
A thing to note is that Red Dot does not allow direct AJAX requests to their servers to do the tokenization. Instead, you will need to set up a separate highly secure proxy server, where you will be sending all the request params and the server just forwards them to Red Dot for tokenization. Below is the controller code for that server:
require 'net/http'
require 'uri'
class RedDotController < ApplicationController
def token
uri = URI.parse(api_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri, 'Content-Type' => 'application/json')
request.body = tokenization_params.to_json
response = http.request(request)
response_json = JSON.parse(response.body)
render json: response_json,
status: (response_json['response_code'] == '0' ? :ok : :unprocessable_entity)
end
private
def api_url
Rails.env.production? ?
'https://secure.reddotpayment.com/service/token-api' :
'https://secure-dev.reddotpayment.com/service/token-api'
end
def tokenization_params
params.permit(
:mid,
:order_id,
:api_mode,
:transaction_type,
:payer_name,
:payer_email,
:ccy,
:card_no,
:exp_date,
:cvv2,
:signature
)
end
end
When you have all the card details from the user, you will need to generate the signature
for your request. If you are using a modern browser, then you can use WebCrypto API (window.crypto
) to do that. Else, you can download the algorithm in JavaScript from here and include it in your application. Below code assumes window.crypto
is defined in your browser.
window.SHA512 = (function() {
function SHA512() {}
SHA512.algorithm = 'SHA-512';
SHA512.crypto = window.crypto || window.msCrypto;
SHA512.digestPromise = function(input) {
if (!SHA512.crypto.subtle) {
return null;
}
return crypto.subtle.digest({
name: SHA512.algorithm
}, SHA512.toUint8Array(input));
};
SHA512.toUint8Array = function(input) {
var bytes, i;
bytes = new Uint8Array(input.length);
i = 0;
while (i < input.length) {
bytes[i] = input.charCodeAt(i);
i++;
}
return bytes;
};
SHA512.toString = function(input) {
var c, dataView, hex, i, len;
dataView = new DataView(input);
hex = '';
i = 0;
len = dataView.byteLength;
while (i < len) {
c = dataView.getUint8(i).toString(16);
if (c.length < 2) {
c = "0" + c;
}
hex += c;
i++;
}
return hex;
};
return SHA512;
})();
var params = { payer_name: 'Jagdeep Singh',
payer_email: '[email protected]',
ccy: 'SGD',
card_no: '4111111111111111',
exp_date: '052023',
cvv2: '123'
mid: '1111110001',
order_id: 'ord10001',
api_mode: 'direct_token_api',
transaction_type: 'C' }
// Generate signature:
// 1. Sort the keys of params hash
// 2. Concatenate the values (sorted by keys)
// 3. Append the secret key to result of (2)
// 4. Encrypt it using SHA-512 algorithm to generate the signature
var sortedKeys = Array.from(Object.keys(params).sort());
input = '';
sortedKeys.forEach(function(key) {
return input += params[key];
});
input += SECRET_KEY;
signaturePromise = SHA512.digestPromise(input);
signaturePromise.then(function(hash) {
params['signature'] = SHA512.toString(hash);
$.ajax({
url: 'https://your-proxy-server.com/reddot/token',
type: 'GET',
data: params,
dataType: 'json',
success: function(data) {
console.log(data);
},
error: function(jqXHR) {
console.log('Error!');
}
});
});
Sample data
in success
callback of above JavaScript request:
{
"mid": "1111110001",
"transaction_id": "10001_565062251772589934",
"order_id": "ord10001",
"ccy": "SGD",
"token_id": "8407275708254242",
"acquirer_response_code": "0",
"acquirer_response_msg": "OK",
"payer_id": "8407275708254242",
"created_timestamp": "2018-10-18 12:42:54",
"response_code": "0",
"response_msg": "OK",
"request_timestamp": "2018-10-18 12:42:52",
"payer_email": "[email protected]",
"transaction_type": "C",
"signature": "091d322ea59cc88be46b9791afedce0b79fa9fc1...007fe8141e3e7aff89e1f1b0a0d0d3dbe143578ea"
}
created_timestamp
, and request_timestamp
are the times in Timezone '+0800'.
Description | Link |
---|---|
Overview | http://reddotpayment.com/developers/?page_id=151 |
Generate signature | http://reddotpayment.com/developers/?page_id=216 |
Generating payment URL | http://reddotpayment.com/developers/?page_id=231 |
Payment callback | http://reddotpayment.com/developers/?page_id=518 |
Below implementation is based on "Process Flow for Redirect Payment API Silent Order Page (SOP)".
You will need payer_id
and payer_email
from the response of Direct Tokenization to make this request.
api_url = 'https://secure.reddotpayment.com/service/payment-api'. # For non-LIVE environments, use 'https://secure-dev.reddotpayment.com/service/payment-api'
params = {
order_id: 'ord10002',
redirect_url: REDIRECT_URL,
notify_url: NOTIFY_URL,
mid: '1111110001',
api_mode: 'redirection_sop',
payment_type: 'S',
ccy: 'SGD',
amount: 149.99,
payer_id: '8407275708254242',
payer_email: '[email protected]'
}
# Generate signature
input = %i[mid order_id payment_type amount ccy payer_id].map { |k| params[k].to_s }.join. # Order of attributes matter
input += SECRET_KEY
params[:signature] = Digest::SHA512.hexdigest(input)
# Request
uri = URI.parse(api_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri, 'Content-Type' => 'application/json')
request.body = params.to_json
response = http.request(request)
=> #<Net::HTTPOK 200 OK readbody=true>
response_json = JSON.parse(response.body)
=> {"created_timestamp"=>1540382294,
"expired_timestamp"=>1540468694,
"mid"=>"1111110001",
"order_id"=>"ord10002",
"transaction_id"=>"322000327_1112340000644294846",
"payment_url"=>
"https://secure.reddotpayment.com/service/payment/--SERVER--/818439d5d2b10fa802a6e31200a0f49b1455ffbf38bd1c3441cbf1f327c4459a1742c6bf112c7a087ffebf69b",
"response_code"=>0,
"response_msg"=>"successful",
"signature"=>"fe5988fadef0028c084ed53d6bce393de9808...901a9e23b21a8a988d66d843c30029955bdc5d34e"}
# Response is successful is `response_code` is set to `0`
is_success = response_json['response_code'] == 0
order_id
length should not be more than 20 characters.
REDIRECT_URL
is the URL of your application where you expect to GET the users redirected after they confirm payment on bank page. You will receive the query parameter transaction_id
when RDP redirects users to it. There, you can check the status of the payment.
NOTIFY_URL
is the URL where you will handle the webhook triggered by RDP when the status of payment is changed. This should be configured to receive POST request.
Note: By default, a merchant also needs another param cvv2
to make this request. You can ask the support to disable it for your merchant.
You need to handle the incoming GET
request to the REDIRECT_URL
provided by you in previous step.
class RedDotPaymentsController < ApplicationController
before_filter :verified_3ds?, only: :callback
def callback
do_this_on_payment_success
end
private
def verified_3ds?
@txn = fetch_transaction(params.require(:transaction_id)) # Refer section "2.3 Fetch transaction" below
return if @txn['response_code'].to_s == '0' # Success
respond_with_error # Failure
end
end
For the NOTIFY_URL you passed in payment URL request, you can simply return a success response from your action, if you have already handled the callback.
def notify
head :ok
end
All the steps for authorize are same as purchase, except for using 'A'
(instead of 'S'
) as payment_type
in request for payment URL generation.
api_url = 'https://secure.reddotpayment.com/service/Merchant_processor/query_redirection'. # For non-LIVE environment, use 'https://secure-dev.reddotpayment.com/service/Merchant_processor/query_redirection'
params = {
request_mid: '1111110001',
transaction_id: TRANSACTION_ID
}
# Generate signature
input = %i[request_mid transaction_id].map { |k| params[k].to_s }.join. # Order of attributes matter
input += SECRET_KEY
params[:signature] = Digest::SHA512.hexdigest(input)
# Request
uri = URI.parse(api_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri, 'Content-Type' => 'application/json')
request.body = params.to_json
response = http.request(request)
=> #<Net::HTTPOK 200 OK readbody=true>
response_json = JSON.parse(response.body)
=> {"mid"=>"1111110001",
"transaction_id"=>TRANSACTION_ID,
"order_id"=>"ord10002",
"acquirer_transaction_id"=>"123456",
"request_amount"=>"149.99",
"request_ccy"=>"SGD",
"authorized_amount"=>"149.99",
"authorized_ccy"=>"SGD",
"response_code"=>0,
"response_msg"=>"successful",
"acquirer_response_code"=>"",
"acquirer_response_msg"=>"",
"acquirer_authorization_code"=>"",
"created_timestamp"=>"2018-10-25 14:45:06",
"acquirer_created_timestamp"=>"2018-10-25 14:44:53",
"request_timestamp"=>"2018-10-25 14:44:53",
"request_mid"=>"1111110001",
"payer_id"=>"c3c61aa60485d...32b6e9d5fd2",
"transaction_type"=>"S",
"signature"=>"40a9882258b25ba1c172ffedf7f1ea4879e4797abb...1446afca54bf907af91e24b9ad78f1697e903a5fb8cf2"}
All the timestamp fields have time in Timezone '+0800'.
Description | Link |
---|---|
Overview | http://reddotpayment.com/developers/?page_id=548 |
API Request and Response | http://reddotpayment.com/developers/?page_id=554 |
api_url = 'https://connect.reddotpayment.com/instanpanel/api/payment' # For non-LIVE environments, use 'https://test.reddotpayment.com/instanpanel/api/payment'
params = {
mid: '1111110001',
transaction_id: TRANSACTION_ID,
order_number: ORDER_ID,
currency: 'SGD',
amount: 99.49,
response_type: 'json',
action_type: 'capture'
}
# Generate signature
input_ary = params.keys.sort.map { |k| "#{k}=#{params[k]}" }
input_ary << "secret_key=#{SECRET_KEY}"
input = input_ary.join('&')
params[:signature] = Digest::SHA512.hexdigest(input)
# Request
uri = URI.parse(api_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri, 'Content-Type' => 'application/json')
request.body = params.to_json
response = http.request(request)
=> #<Net::HTTPOK 200 OK readbody=true>
ORDER_ID
is the order_id
passed in API request for authorization.
Void differs from capture only in the params
. You don't need to pass currency
and amount
for voiding a transaction.
params = {
mid: '1111110001',
transaction_id: TRANSACTION_ID,
order_number: ORDER_ID,
response_type: 'json',
action_type: 'void'
}
Refund differs from capture only in param action_type
.
params = {
mid: '1111110001',
transaction_id: TRANSACTION_ID,
order_number: ORDER_ID,
currency: 'SGD',
amount: 99.49,
response_type: 'json',
action_type: 'refund'
}
Contents:
- 4.1 Setup account and generate keys
- 4.2 Generate payment page URL
- 4.3 Handle tokenization callback
- 4.4 Make a charge with tokenized card
- 4.5 Capture a payment
- 4.6 Void a payment
- 4.7 Refund a payment
Get credentials for Connect 2 Portal from RDP. You will need Company name, Email and a Password to access the admin panel.
Create a Tokenization page by providing a Redirect URL (where RDP will make a POST callback request with encrypted card token). It will generate the API credentials. Note down the following:
- Merchant ID- xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- Client Key- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- Client Secret- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Now, let's make an API request to generate the URL for page where customers will enter the card details.
api_url = "https://connect2.api.reddotpay.sg/v1/payments/token/authTokenUrl/#{MERCHANT_ID}"
headers = { 'Content-Type' => 'application/json' }
params = {
clientKey: CLIENT_KEY,
clientSecret: CLIENT_SECRET,
returnUrl: 'https://domain.com/path/to/merchant'
}
response = HTTParty.post(
api_url,
headers: headers,
body: params.to_json
)
response.parsed_response
=> {"token"=>"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVLTkzODQtYU3IiwiaWF0IjoxNTY4MDE1MjE3LCJleHAiOjE1NjgwMTYxMTd9.fNYPN0RSNsqMyt32cLu21WfmLz3CIyXKKxaqn6Od5gk", "pageId"=>"bccc0ecb-e03d-9aa9-9384-a02aebaba4e7", "pageURI"=>"https://connect2.reddotpay.sg/m/d6e01d1d-aac0-abcd-9fff-4beae099fba7#/tokenize/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVLTkzODQtYU3IiwiaWF0IjoxNTY4MDE1MjE3LCJleHAiOjE1NjgwMTYxMTd9.fNYPN0RSNsqMyt32cLu21WfmLz3CIyXKKxaqn6Od5gk", "rdpCustomerReference"=>"d211f4bf-612a-abcd-dcba-9fa975d4bd39"}
returnUrl
represents the URL where customers will be taken to when they click "Back to merchant" button after their card is tokenized.
Store rdpCustomerReference
in your database for referencing in tokenization callback. It is unique for every tokenization request.
pageURI
is the URL to which you need customers to redirect to for entering card details.
Test cards:
Card Number | Expiry | CVV |
---|---|---|
4111 1111 1111 1111 | 09/2029 | 123 |
4532 0818 6469 8195 | 09/2029 | 123 |
After customer enters the card details on payment page (at pageURI
) and clicks "Submits", card details are tokenized at RDP server and a POST callback request is made back to the application with the result.
class RDPController < ApplicationController
def token_callback
params
# => {"messageToken"=>"eyJhbGciOiJIU6IkpXVCJ9.eyJkYXRlQWRkZWQiOiIyMDE5LTA5LTg3ZmYtZDc1ZS00ZDdhLTlkMGMtNmE3NTFjMGQwZmU3IiwiY2FyZFRva2VuRXhwaXJlc1VuaXhEYXRlIjoxNTc1OTUyNjAzLCJpYXQiOjE1NjgxNzY2MTB9.08TUGmmYa0LQvUsHDTPIBq-lR3jjc", "pageId"=>"bccc0ecb-e03d-abcd-1234-a02aebaba4e7"}
end
end
pageId
is the same as returned in response of 4.2.
messageToken
is a JWT token. It contains all the details like card holder name, last digits of card, a card token, etc. Decrypt it using ruby library ruby-jwt.
def token_callback
JWT.decode(params[:messageToken], CLIENT_SECRET)
# => [{"dateAdded"=>"2019-09-11 04:35:58", "paymentType"=>"", "ip"=>"0.0.0.0", "returnUrl"=>"https://domain.com/path/to/save/card/token", "rdpCustomerReference"=>"d211f4bf-612a-abcd-dcba-9fa975d4bd39", "description"=>"", "dateProcessed"=>"", "cardInfo"=>{"cardHolderName"=>"Jagdeep Singh", "network"=>"Visa", "last4Digits"=>"1111"}, "cardToken"=>"411111-214287ff-d75e-abcd-1234-6a751c0d0fe7", "cardTokenExpiresUnixDate"=>1575952603, "iat"=>1568176610}, {"alg"=>"HS256", "typ"=>"JWT"}]
end
Below are some of the important fields:
rdpCustomerReference
- It is the same as returned in response of 4.2.cardInfo
cardHolderName
- Name on cardnetwork
- Card typelast4Digits
cardToken
- Token to be used for making charges on the cardcardTokenExpiresUnixDate
- Expiry date ofcardToken
(normally 3 months in future)
auth = [CLIENT_KEY, CLIENT_SECRET].join(':')
headers = {
'Content-Type' => 'application/x-www-form-urlencoded',
'Authorization' => "Basic #{Base64.strict_encode64(auth)}"
}
response = HTTParty.post(
'https://secure.api.reddotpay.sg/oauth2/token',
headers: headers,
body: { grant_type: 'client_credentials' }
)
response.code
=> 200
response.parsed_response
=> {"access_token"=>"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjgyMDQyMhwnDw_kytSWcgeoYzRcqpNStSW1Qa3LnTv7alBM-BxBw-MXDaR1iPRX3a9iGUJZcgoKxVsVn_Y4YsfTg6lqBjDlgdsK51UCEWV8Jw", "expires_in"=>1568204206, "token_type"=>"Bearer"}
Below is the request to make a purchase transaction using cardToken
:
headers = {
'Content-Type' => 'application/json',
'Authorization' => ACCESS_TOKEN,
'Accept' => 'application/json'
}
params = {
description: "My first order",
amount: 95.49,
currency: 'SGD',
merchant: 'rid:mam:merchant/MERCHANT_ID',
account: 'rid:mam:account/ACCOUNT_ID',
customer: {
token: 'rid:card:repo/TOKENIZATION_REPO_ID/token/CARD_TOKEN'
},
reference: '123456'
}
response = HTTParty.post(
'https://cardpay.api.reddotpay.sg/v1/order',
headers: headers,
body: params.to_json
)
response.code
=> 201
response.parsed_response
=> {"id"=>"0d09d133c8847fc6599f253a7cc639be", "account"=>{"rid"=>"rid:mam:account/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "gateway"=>"maybank"}, "merchant"=>"rid:mam:merchant/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "authorize"=>{"amount"=>95.49, "currency"=>"SGD"}, "capture"=>{"amount"=>95.49, "currency"=>"SGD"}, "description"=>"My first order", "state"=>"capture", "customer"=>{"token"=>"rid:card:repo/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/token/xxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}, "transactions"=>[{"id"=>"af1d0c2a93b0ee8bdeb7af77ddab7b98", "xid"=>"123456", "ledger"=>"rid:veritas:entry/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "amount"=>95.49, "currency"=>"SGD", "action"=>"auto-capture", "status"=>"success", "authCode"=>"657300", "date"=>{"created"=>"2019-09-13T06:21:27Z"}, "acquirer"=>{"code"=>"0", "message"=>"APPROVED OR COMPLETED"}}], "date"=>{"created"=>"2019-09-13T06:21:31Z"}}
ACCESS_TOKEN
in headers
is the access token generated in 4.4.1.
In the params
:
description
- The doc says this attribute is optional, but the request fails if we don't pass it.merchant
-MERCHANT_ID
is Merchant ID generated in 4.1 above.account
-ACCOUNT_ID
(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) is something RDP will provide you. Contact their support.customer
token
-TOKENIZATION_REPO_ID
(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) can be found in the browser URL when you visit your tokenization page on Connect 2 portal.CARD_TOKEN
is thecardToken
from 4.3 above.
reference
- It must be a unique string.
Whether the payment will be auto-captured on not, it depends on the settings of your account. Please check those with RDP. You can disable auto-capture and then every payment will be authorized only. You will have to manually capture them.
Below is the sample response for authorized transaction:
response.parsed_response
=> {"id"=>"29812ab6ecd5393e226921b8039cc134", "account"=>{"rid"=>"rid:mam:account/xxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "gateway"=>"maybank"}, "merchant"=>"rid:mam:merchant/xxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "authorize"=>{"amount"=>95.49, "currency"=>"SGD"}, "description"=>"00168-1568362255", "state"=>"authorize", "customer"=>{"token"=>"rid:card:repo/xxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/token/xxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}, "transactions"=>[{"id"=>"d780471012adfc67973918f78913a139", "xid"=>"123456", "ledger"=>"rid:veritas:entry/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "amount"=>95.49, "currency"=>"SGD", "action"=>"authorize", "status"=>"success", "authCode"=>"657300", "date"=>{"created"=>"2019-09-13T08:10:52Z"}, "acquirer"=>{"code"=>"0", "message"=>"APPROVED OR COMPLETED"}}], "date"=>{"created"=>"2019-09-13T08:10:57Z"}}
headers = {
'Content-Type' => 'application/json',
'Authorization' => ACCESS_TOKEN,
'Accept' => 'application/json'
}
params = {
amount: 95.49,
currency: 'SGD'
}
response = HTTParty.post(
'https://cardpay.api.reddotpay.sg/v1/order/ORDER_ID/capture',
headers: headers,
body: params.to_json
)
response.parsed_response
=> {"id"=>"c9953ecab569f8ab932746eb4e4f5594", "account"=>{"rid"=>"rid:mam:account/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "gateway"=>"maybank"}, "merchant"=>"rid:mam:merchant/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "authorize"=>{"amount"=>95.49, "currency"=>"SGD"}, "capture"=>{"amount"=>95.49, "currency"=>"SGD"}, "state"=>"capture", "customer"=>{"token"=>"rid:card:repo/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/token/xxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}, "transactions"=>[{"id"=>"489ed57d63fcf98c89cf7b31aad6a06e", "xid"=>"123456", "ledger"=>"rid:veritas:entry/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "amount"=>95.49, "currency"=>"SGD", "action"=>"capture", "status"=>"success", "date"=>{"created"=>"2019-09-13T11:14:24Z"}, "acquirer"=>{"code"=>"0", "message"=>"APPROVED OR COMPLETED"}}], "date"=>{"created"=>"2019-09-13T11:14:24Z"}}
ORDER_ID
can be found at response.parsed_response['id']
in 4.4.2 above.
4.6 Void a payment
response = HTTParty.post(
'https://cardpay.api.reddotpay.sg/v1/order/ORDER_ID/void',
headers: { 'Authorization' => ACCESS_TOKEN }
)
response.code
=> 201
response.parsed_response
=> {"id"=>"2a6184fa1497db409311ca0d31806807", "account"=>{"rid"=>"rid:mam:account/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "gateway"=>"maybank"}, "merchant"=>"rid:mam:merchant/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "state"=>"close", "customer"=>{"token"=>"rid:card:repo/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/token/xxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}, "transactions"=>[{"id"=>"850a34576b2f5caf907c3c4ae5a85ef1", "xid"=>"123456", "ledger"=>"rid:veritas:entry/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "action"=>"void", "status"=>"success", "date"=>{"created"=>"2019-09-20T10:43:43Z"}, "acquirer"=>{"code"=>"0", "message"=>"APPROVED OR COMPLETED"}}]}
4.7 Refund a payment
headers = {
'Content-Type' => 'application/json',
'Authorization' => ACCESS_TOKEN,
'Accept' => 'application/json'
}
params = {
amount: 49.49,
currency: 'SGD'
}
response = HTTParty.post(
'https://cardpay.api.reddotpay.sg/v1/order/ORDER_ID/refund',
headers: headers,
body: params.to_json
)
response.code
=> 201
response.parsed_response
=> {"id"=>"41b0cf1597373aef00edd5cfa5ce1806", "account"=>{"rid"=>"rid:mam:account/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "gateway"=>"maybank"}, "merchant"=>"rid:mam:merchant/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "authorize"=>{"amount"=>95.49, "currency"=>"SGD"}, "capture"=>{"amount"=>95.49, "currency"=>"SGD"}, "refund"=>{"amount"=>49.49, "currency"=>"SGD"}, "state"=>"refund", "customer"=>{"token"=>"rid:card:repo/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/token/xxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}, "transactions"=>[{"id"=>"e563cec5ac9c29ba8964bc7f07117d2a", "xid"=>"12345", "ledger"=>"rid:veritas:entry/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "amount"=>49.49, "currency"=>"SGD", "action"=>"refund", "status"=>"success", "date"=>{"created"=>"2019-09-20T11:17:27Z"}, "acquirer"=>{"code"=>"0", "message"=>"APPROVED OR COMPLETED"}}]}