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:

ParameterTypeDescription
AcceptStringRequiredThis 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
AuthorizationStringRequiredSHA256 generated with a secret key to guarantee request authenticity. Format: {store-id}:{hash}
Content-TypeStringRequiredOnly application/json is accepted at the moment
Store-id and secret-key are provided by your Account Manager.

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

ParameterTypeDescription
transaction-idIntegerRequiredTransaction identifier in PagSeguro
notify-urlStringRequiredURL used to notify the Merchant. This URL must bind ports 80 or 443. Format: http or https URL format
amountFloatOptionalAmount 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-modeIntegerOptionalParameter 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
referenceStringOptionalMerchant 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.

ParameterTypeDescription
refund-idStringRefund 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.

1311

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 REJECTED

Error 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.

943

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.

692

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

ParameterDescription
notification-typeAssumes the value “refund”
refund-idID of the refund in PagSeguro
transaction-idID 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

CodeKeyDescription
20601internal_server_error
20604partner_not_foundThe store-id sent does not exist
20605payment_does_not_accept_refundThe payment method used in the transaction does not accept refunds
20607refund_already_requestedA refund for the referred transaction is already being processed
20608refund_amount_is_greater_than_limitAn amount smaller than the transaction value + refund already requested is required
20609refund_amount_is_greater_than_transactionThe amount sent is greater than the transaction value
20610refund_not_foundRefund not found
20612service_refund_access_not_authorizedThe merchant does not have permission to request refunds
20613transaction_is_resellerMerchant category does not allow refunds
20614transaction_not_foundTransaction not found
20615transaction_status_not_accept_refundThe current status of the transaction does not allow refunds
20621expired_refund_requestDeadline for refund exceeded
20622partial_refund_not_allowedPartial refund not allowed
20698Property missing, invalid constraint / type or invalid data.
20699unknown_error

Transaction Search API errors

CodeKeyDescription
22100initial_order_date_invalidInitial order date has an invalid format
22101final_order_date_invalidFinal order date has an invalid format
22102initial_payment_date_invalidInitial payment date has an invalid format
22103final_payment_date_invalidFinal payment date has an invalid format
22104initial_last_status_change_date_invalidInitial last status change date has an invalid format
22105final_last_status_change_date_invalidFinal last status change date has an invalid format
22106initial_order_date_is_mandatory_to_filter_by_final_order_dateInitial order date is mandatory to filter by final order date
22107final_order_date_must_be_greater_than_initial_order_dateInitial order date must be greater than final order date
22108initial_payment_date_is_mandatory_to_filter_by_final_payment_dateInitial payment date is mandatory to filter by final payment date
22109final_payment_date_must_be_greater_than_initial_payment_dateInitial payment date must be greater than final payment date
22110initial_last_status_change_date_is_mandatory_to_filter_by_final_last_status_change_dateInitial last status change date is mandatory to filter by final last status change date
22111final_last_status_change_date_must_be_greater_than_initial_last_status_change_dateInitial last status change date must be greater than final last status change date
22112final_order_date_range_exceededOrder date range date exceeded
22113final_payment_date_range_exceededOrder payment range date exceeded
22114final_last_status_change_date_range_exceededOrder last status change range date exceeded
22115page_invalidPage has an invalid format
22116max_page_results_invalidMax page results has an invalid format
22117any_initial_date_is_mandatory_for_multiple_recordsTransactionCode or any initial-date is mandatory
22118status_invalidTransaction status provided is invalid
22119Status_not_existsTransaction status provided does not exists