Refund
Introduction
PagSeguro API offers an option to Merchant request the refund of a transaction.
A transaction needs to be in status Delivered/Complete in PagSeguro in order to be refunded. The payment method/country of the transaction must be one of which PagSeguro accepts refund. Appendix II has a list of payment methods that are eligible for refund.
Header Specification
For a new API request it is mandatory to format the header as described below:
Parameter | Type | Description | |
---|---|---|---|
Accept | String | Required | This parameter informs the API version, data format (JSON) and encoding. The value will depend on which API you are calling. Refund Create: application/vnd.boacompra.com.v2+json; charset=UTF-8 |
Authorization | String | Required | SHA256 generated with a secret key to guarantee request authenticity. Format: {store-id}:{hash} |
Content-Type | String | Required | Only application/json is accepted at the moment |
Header Example
POST / HTTP 1.1
Host: api.boacompra.com
Accept: application/vnd.boacompra.com.v2+json; charset=UTF-8
Authorization: 10: 52e7178dea75ae0e71e0f8c2379e0278beb7e9d091763ee0a64e6719d2df0fc2
Content-Type: application/json
Code Example
public class Header {
private String secretKey = "ABCDE0987";
private String storeId = "10";
private String contentMD5;
private String httpVerb;
public Header(String content, String url) throws NoSuchAlgorithmException, MalformedURLException, UnsupportedEncodingException {
this.setContentMd5(content);
this.setHttpVerb(new URL(url));
}
private void setHttpVerb(URL url) {
this.httpVerb = url.getPath() + (url.getQuery() != null ? '?' + url.getQuery() : "");
}
private void setContentMd5(String content) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance("MD5");
byte messageDigest[] = md.digest(content.getBytes("UTF-8"));
this.contentMD5 = new BigInteger(1,messageDigest).toString(16);
}
private String generateAuthorization() throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
final String data = this.httpVerb+this.contentMD5;
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(this.secretKey.getBytes("UTF8"), "HmacSHA256"));
return Hex.encodeHexString(mac.doFinal(data.getBytes("UTF-8")));
}
public HashMap<String,String> generateHeader() throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
HashMap<String, String> headers = new HashMap<>();
headers.put("Accept", "application/vnd.boacompra.com.v2+json; charset=UTF-8");
headers.put("Content-Type", "application/json");
headers.put("Authorization", this.storeId+':'+this.generateAuthorization());
return headers;
}
}
String content = "{\"transaction-id\":123456789,\"amount\":10.57,\"notify-url\":\"https://virtualstore.com/notifications\",\"test-mode\":0}";
Header header = new Header(content, "https://api.boacompra.com/refunds");
HashMap<String, String> headerMap = header.generateHeader();
System.out.println(Arrays.asList(headerMap));
<?php
class header
{
private $secretKey = 'ABCDE0987';
private $storeId = 10;
public function __construct($content, $url)
{
$this->setContentMd5($content);
$this->setHttpVerb($url);
}
private function setContentMd5($content)
{
$this->contentMd5 = md5($content);
}
private function setHttpVerb($url)
{
if (parse_url($url, PHP_URL_QUERY)) {
$this->httpVerb = parse_url($url, PHP_URL_PATH).'?'.parse_url($url, PHP_URL_QUERY);
} else {
$this->httpVerb = parse_url($url, PHP_URL_PATH);
}
}
private function generateAuthorization()
{
return hash_hmac(
'sha256',
$this->httpVerb . $this->contentMd5,
$this->secretKey
);
}
public function generateHeader()
{
$headers = array(
'Accept' => 'application/vnd.boacompra.com.v2+json; charset=UTF-8',
'Content-Type' => 'application/json',
'Authorization' => $this->storeId . ':' . $this->generateAuthorization()
);
return $headers;
}
}
echo 'POST EXAMPLE <br />';
$content = '{"transaction-id":123456789,"amount":10.57,"notify-url":"https://virtualstore.com/notifications","test-mode":0}';
$headerPost = new header($content, 'https://api.boacompra.com/refunds');
print_r($headerPost->generateHeader());
require 'uri'
require 'openssl'
require 'digest/md5'
class Header
SECRET_KEY = 'ABCDE0987'
STORE_ID = 10
attr_reader :contentMD5, :httpVerb
def initialize(content, url)
setContentMD5(content)
setHttpVerb(url)
end
private
def setContentMD5(content)
@contentMD5 = Digest::MD5.hexdigest(content).to_s
end
private
def getQueryString(url)
uri = URI(url)
url.to_s.empty? || uri.query.nil? ? '' : '?' + uri.query
end
private
def setHttpVerb(url)
uri = URI::parse(url)
@httpVerb = getQueryString(url).to_s.empty? ? uri.path : uri.path + "?" + getQueryString(url)
end
private
def generateAuthorization()
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), SECRET_KEY, @httpVerb + @contentMD5)
end
public
def generateHeader()
headers = {
"Accept" => 'application/vnd.boacompra.com.v2+json; charset=UTF-8',
"Content-Type" => 'application/json',
"Authorization" => STORE_ID.to_s + ":" + generateAuthorization()
}
headers
end
end
puts '<pre>POST EXAMPLE <br />'
content = '{"transaction-id":123456789,"amount":10.57,"notify-url":"https://virtualstore.com/notifications","test-mode":0}';
headerGet = Header.new(content, 'https://api.boacompra.com/refunds')
puts headerGet.generateHeader()
"""Python 2.7"""
from urlparse import urlparse
import hashlib
import hmac
import md5
class Header:
__secretKey = '123'
__storeId = 10
def __init__(self, content, url):
self.__setHttpVerb(url)
self.__setContentMd5(content)
def __setHttpVerb(self, url):
urlParsed = urlparse(url)
self.__httpVerb = urlParsed.path + urlParsed.query
def __setContentMd5(self, content):
self.__contentMd5 = md5.new(content).hexdigest()
def __generateAuthorization(self):
return hmac.new(
self.__secretKey,
self.__httpVerb + self.__contentMd5,
hashlib.sha256
).hexdigest()
def generateHeader(self):
return {
'Accept': 'application/vnd.boacompra.com.v2+json; charset=UTF-8',
'Content-Type': 'application/json',
'Authorization': str(self.__storeId) + ':' + self.__generateAuthorization()
}
from Header import Header
content = '{"transaction-id":123456789,"amount":10.57,"notify-url":"https://virtualstore.com/notifications","test-mode":0}'
url = 'https://api.boacompra.com/refunds'
a = Header(content, url)
print a.generateHeader()
"""Python 3.x"""
from urllib.parse import urlparse
import hashlib
import hmac
class Header:
__secretKey = '123'
__storeId = 10
def __init__(self, content, url):
self.__setHttpVerb(url)
self.__setContentMd5(content)
def __setHttpVerb(self, url):
urlParsed = urlparse(url)
self.__httpVerb = urlParsed.path + urlParsed.query
def __setContentMd5(self, content):
self.__contentMd5 = hashlib.md5(content.encode()).hexdigest()
def __generateAuthorization(self):
authContent = self.__httpVerb + self.__contentMd5
return hmac.new(
self.__secretKey.encode(),
authContent.encode(),
hashlib.sha256
).hexdigest()
def generateHeader(self):
return {
'Accept': 'application/vnd.boacompra.com.v2+json; charset=UTF-8',
'Content-Type': 'application/json',
'Authorization': str(self.__storeId) + ':' + self.__generateAuthorization()
}
from Header import Header
content = '{"transaction-id":123456789,"amount":10.57,"notify-url":"https://virtualstore.com/notifications","test-mode":0}'
url = 'https://api.boacompra.com/refunds'
a = Header(content, url)
print(a.generateHeader())
Refund Request API
This request must be made in order to create a refund for a given transaction. This only creates the refund: the processing and finishing of this refund is made by PagSeguro directly through the payment provider.
Host: https://api.boacompra.com/refunds
Method: POST
Input parameters
Parameter | Type | Description | |
---|---|---|---|
transaction-id | Integer | Required | Transaction identifier in PagSeguro |
notify-url | String | Required | URL used to notify the Merchant. This URL must bind ports 80 or 443. Format: http or https URL format |
amount | Float | Optional | Amount to be refunded. If not sent, the refund will be processed for the entire value of the transaction. For partial refunds, the amount parameter must be sent. Format: 2000.00 |
test-mode | Integer | Optional | Parameter used to indicate that a transaction will be processed in test mode. Can be used the value 1 for sandbox or 0 for production environment. If not set assumes value 0. Format: possible entries are 0 or 1 |
reference | String | Optional | Merchant refund identifier. Limit of 64 characters. |
JSON Request Body Example
{
"transaction-id": 123456789,
"amount": 10.57,
"notify-url": "https://virtualstore.com/notifications",
"test-mode": 0,
"reference": "BC-380465"
}
Success Response
HTTP Status code: 201
In case of success, the refund process will be started and the transaction will be set to processing refund status.
Also, a “Location” parameter will be informed in the header with the transaction URI location.
Parameter | Type | Description |
---|---|---|
refund-id | String | Refund identifier code generated by PagSeguro |
Response header example
HTTP/1.1 201 Created
Content-type: application/vnd.boacompra.com.v2+json; charset=UTF-8
Location: /transactions/123456
JSON Response example
{
"refund-id":12345
}
In a few payment methods, an e-mail will be sent to the end user with URL so he can fulfill its refund information. In this case, he can choose refund through bank transfer. This process is transparent to the merchant.
When accessing the URL, a form similar to the following image will be displayed.
After the refund is complete, a notification will be sent via notify API to inform the conclusion of the refund. Please refer to the notification section for further details.
The payer has 7 days to fulfill the form with their information, otherwise the refund will change its status to REJECTEDError response
In case of errors in the request, expect a HTTP Status Code different from 201. The body response also contains an error object with the description and an error code
Json Response example
{
"errors": [
{
"code": "20614",
"description": "transaction_not_found "
}
]
}
The full list of errors can be found in Appendix I.
It is possible that you encounter one or more errors in an error array, which will have a unique code number. In those cases, there is a problem with the Request Body: the need of a property or a constraint is not met.
Json Response example
{
"errors": [
{
"property": "transaction-id",
"constraint": "required",
"code": 20698,
"description": "The property transaction-id is required"
},
{
"property": "amount",
"constraint": "minimum",
"minimum": 0.01,
"code": 20698,
"description": "Must have a minimum value of 0.01"
}
]
}
Transaction Search API
The API can return information about one specific transaction or a list of transactions, based on the search criteria requested via API.
There’s a separate guide for the Transaction Search API.
Refund in Billing Partner
You can view refund requests in the billing-partner interface for both live transactions and test transactions. Also, there’s a field for filtering specifically by the unique Refund ID number.
In the transaction page a new section, called Refunds, was added. It contains a summary of refund requests.
Test Mode
To use the Refund in test mode you will need to have transactions delivered with the “test-mode” parameter set to true, after sending the request for Refund is it possible to simulate the notification of success and failure in the billing-partner interface.
In the Transaction Test menu it’s possible to find the transaction for which the refund request was made.
In the refund list you can simulate the notification for Success and Failure by clicking in the respective button and a notification will be sent to URL informed on the notify-url refund parameter.
Notification
When a Refund is finished successfully or is rejected for some reason, the merchant will receive a notification in the notification url first sent when creating the refund.
After receiving the notification, the merchant will have to consult the transaction (see section Transaction Search API) and could take an action accordingly its status.
Base URL: notify-url
parameter sent when creating the refund
Method: POST
Notification Object
Parameter | Description |
---|---|
notification-type | Assumes the value “refund” |
refund-id | ID of the refund in PagSeguro |
transaction-id | ID of the transaction in PagSeguro |
Body Example
{
"notification-type": "refund",
"refund-id": 12345,
"transaction-id": 75040384
}
Payment Methods Available for Refund
The list of payments and countries with refund available can be found on Available payment list.
Refund errors
Code | Key | Description |
---|---|---|
20601 | internal_server_error | |
20604 | partner_not_found | The store-id sent does not exist |
20605 | payment_does_not_accept_refund | The payment method used in the transaction does not accept refunds |
20607 | refund_already_requested | A refund for the referred transaction is already being processed |
20608 | refund_amount_is_greater_than_limit | An amount smaller than the transaction value + refund already requested is required |
20609 | refund_amount_is_greater_than_transaction | The amount sent is greater than the transaction value |
20610 | refund_not_found | Refund not found |
20612 | service_refund_access_not_authorized | The merchant does not have permission to request refunds |
20613 | transaction_is_reseller | Merchant category does not allow refunds |
20614 | transaction_not_found | Transaction not found |
20615 | transaction_status_not_accept_refund | The current status of the transaction does not allow refunds |
20621 | expired_refund_request | Deadline for refund exceeded |
20622 | partial_refund_not_allowed | Partial refund not allowed |
20698 | Property missing, invalid constraint / type or invalid data. | |
20699 | unknown_error |
Transaction Search API errors
Code | Key | Description |
---|---|---|
22100 | initial_order_date_invalid | Initial order date has an invalid format |
22101 | final_order_date_invalid | Final order date has an invalid format |
22102 | initial_payment_date_invalid | Initial payment date has an invalid format |
22103 | final_payment_date_invalid | Final payment date has an invalid format |
22104 | initial_last_status_change_date_invalid | Initial last status change date has an invalid format |
22105 | final_last_status_change_date_invalid | Final last status change date has an invalid format |
22106 | initial_order_date_is_mandatory_to_filter_by_final_order_date | Initial order date is mandatory to filter by final order date |
22107 | final_order_date_must_be_greater_than_initial_order_date | Initial order date must be greater than final order date |
22108 | initial_payment_date_is_mandatory_to_filter_by_final_payment_date | Initial payment date is mandatory to filter by final payment date |
22109 | final_payment_date_must_be_greater_than_initial_payment_date | Initial payment date must be greater than final payment date |
22110 | initial_last_status_change_date_is_mandatory_to_filter_by_final_last_status_change_date | Initial last status change date is mandatory to filter by final last status change date |
22111 | final_last_status_change_date_must_be_greater_than_initial_last_status_change_date | Initial last status change date must be greater than final last status change date |
22112 | final_order_date_range_exceeded | Order date range date exceeded |
22113 | final_payment_date_range_exceeded | Order payment range date exceeded |
22114 | final_last_status_change_date_range_exceeded | Order last status change range date exceeded |
22115 | page_invalid | Page has an invalid format |
22116 | max_page_results_invalid | Max page results has an invalid format |
22117 | any_initial_date_is_mandatory_for_multiple_records | TransactionCode or any initial-date is mandatory |
22118 | status_invalid | Transaction status provided is invalid |
22119 | Status_not_exists | Transaction status provided does not exists |
Updated about 2 years ago