Transaction Search and Notification

Introduction

We put together this integration manual to provide you all of the information about the technical aspects of transactions notifications and searches.


Work Flow

Transaction Status Notification Change API

3335

How it Works

  1. PagSeguro notifies Merchant that a transaction status has changed

  2. Merchant requests the transaction information provided in the notification to PagSeguro

  3. PagSeguro responds back with the transaction information

In case PagSeguro responds the transaction as COMPLETE Merchant needs to deliver the purchase to the End User.

Transaction Search API

3335
  1. Merchant requests transaction information

  2. PagSeguro responds back with a list or a single transaction

Header Specification

For all API requests it is mandatory to format the header as described below:

ParameterDescription
AcceptThis parameter informs the API version, data format (JSON) and encoding. Default value is: application/vnd.boacompra.com.v1+json; charset=UTF-8
Accept-LanguageInput language. Default value is en-US.
AuthorizationTo create a request the following information is required: store-id, secret-key, URL Path (e.g. /transactions) and URL Query String (e.g. ?initial_date=yyyy-mm-dd). : The string-authorization is done using hmac-sha256-algorithm. The secret-key is the key parameter. The message parameter is formed by the URL Path and URL Query String concatenated.
Content-Typeapplication/json
Store-id and secret-key are provided by your Account Manager.

Headers Example

Accept: application/vnd.boacompra.com.v1+json; charset=UTF-8
Content-Type: application/json
Accept-Language: en-US
Authorization: 10:05eddbf68e09cb3d339b08a8e478c020d50d7c3604ad3da67def785e9399daaa

Generating the Headers

public class Header {
  private String secretKey = "YOURSECRETKEY";
  private String storeId = "10";
  private String contentMD5;
  private String httpVerb;

  public Header(String url, String content) 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 {
    if (content == "") {
      this.contentMD5 = "";
    }else {
      MessageDigest md = MessageDigest.getInstance("MD5");
      byte messageDigest[] = md.digest(content.getBytes("UTF-8"));
      this.contentMD5 = Base64.encodeBase64String(new BigInteger(1,messageDigest).toString(16).getBytes());
    }
  }

  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.v1+json; charset=UTF-8");
    headers.put("Content-Type", "application/json");
    headers.put("Authorization", this.storeId+':'+this.generateAuthorization());
    headers.put("Accept-Language", "en-US");

    return headers;
  }
}

Header header = new Header("https://api.boacompra.com/transactions/87585840", "");
HashMap<String, String> headerMap = header.generateHeader();
System.out.println(Arrays.asList(headerMap));
<?php

class header {

    private $_secretKey = 'YOURSECRETKEY';
    private $_storeId = '10';

    function __construct($url, $content = '') {
        $this->_setContentMd5($content);
        $this->_setHttpVerb($url);
    }

    private function _setContentMd5($content) {
        if ($content == '') $this->_contentMd5 = '';
        else $this->_contentMd5 = base64_encode(md5($content));
    }

    private function _getQueryString($url){
        $queryString = parse_url($url, PHP_URL_QUERY);
        return empty($queryString) ? '' : '?' . $queryString;
    }

        private function _setHttpVerb($url) {
        $this->_httpVerb = parse_url($url, PHP_URL_PATH) . $this->_getQueryString($url);
    }

    private function _generateAuthorization() {
        return hash_hmac('sha256', $this->_httpVerb . $this->_contentMd5, $this->_secretKey);
    }

    public function generateHeader() {
        $headers = array(
        'Accept' => 'application/vnd.boacompra.com.v1+json; charset=UTF-8',
        'Content-Type' => 'application/json',
        'Authorization' => $this->_storeId.':'.$this->_generateAuthorization(),
        'Accept-Language' => 'en-US'
        );
        return $headers;
    }
}

echo '<pre>'. 'GET EXAMPLE <br />';
$headerGet = new header('https://api.boacompra.com/transactions/87585840', '');

print_r($headerGet->generateHeader());
require 'uri'
require 'base64'
require 'openssl'
require 'digest/md5'

class Header

   SECRET_KEY = 'YOURSECRETKEY'
   STORE_ID = 10

   attr_reader :contentMD5, :httpVerb

   def initialize(url, content = '')
    setContentMD(content)
    setHttpVerb(url)
   end

   private
   def setContentMD(content)
      if content.to_s.empty?
          @contentMD5 = ''
      else
          @contentMD5 = Base64.encode64(Digest::MD5.hexdigest(content)).delete!("\n")
      end
   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 = 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.v1+json; charset=UTF-8',
     "Content-Type"     => 'application/json',
     "Authorization"    => STORE_ID.to_s + ":" + generateAuthorization(),
     "Accept-Language"  => 'en-US'
    }
    headers
   end
end

puts '<pre>GET EXAMPLE <br />'
headerGet = Header.new('https://api.boacompra.com/transactions/87585840', '')
puts headerGet.generateHeader()
"""Boacompra python 2.7"""
import base64
import hashlib
import hmac

from urlparse import urlparse

class Header:
  secretKey = "YOURSECRETKEY"
  storeId = "10"

  def __init__(self, url, content):
    self.setContentMd5(content)
    self.setHttpVerb(url)

  def setContentMd5(self, content):
    self.contentMd5 = '' if content == '' else base64.b64encode(hashlib.md5(content).hexdigest())

  def setHttpVerb(self, url):
    self.httpVerb = '{}''{}'.format(urlparse(url).path, self.getQueryStrint(url))

  def getQueryStrint(self, url):
    return '' if urlparse(url).query == '' else '?{}'.format(urlparse(url).query)

  def generateAuthorization(self):
    return hmac.new(self.secretKey, self.httpVerb + self.contentMd5, hashlib.sha256).hexdigest()

  def generateHeader(self):
    return dict({'Accept':'application/vnd.boacompra.com.v1+json; charset=UTF-8', 'Content-Type':'application/json', 'Authorization': '{}'':{}'.format(self.storeId, self.generateAuthorization()), 'Accept-Language':'en-US'})


"""Boacompra python 3.x"""
import base64
import hashlib
import hmac

from urllib.parse import urlparse

class Header3(object):
  secretKey = "YOURSECRETKEY"
  storeId = "10"

  def __init__(self, url, content):
    self.setContentMd5(content)
    self.setHttpVerb(url)
    self.generateAuthorization()

  def setContentMd5(self, content):
    self.contentMd5 = ''
    if content == ''
    else base64.b64encode(hashlib.md5(content.encode()).hexdigest().encode('ascii')).decode('ascii')

  def setHttpVerb(self, url):
    self.httpVerb = '{}''{}'.format(urlparse(url).path, self.getQueryStrint(url))

  def getQueryStrint(self, url):
    return '' if urlparse(url).query == '' else '?{}'.format(urlparse(url).query)

  def generateAuthorization(self):
    message = bytes('{}''{}'.format(self.httpVerb, self.contentMd5), 'utf-8')
    secret = bytes(self.secretKey, 3 'utf-8')

    return hmac.new(secret, message, hashlib.sha256).hexdigest()

  def generateHeader(self):
    return dict({'Accept':'application/vnd.boacompra.com.v1+json; charset=UTF-8', 'Content-Type':'application/json', 'Authorization': '{}'':{}'.format(self.storeId, self.generateAuthorization()), 'Accept-Language':'en-US'})

Transaction Status Change Notification

Whenever a transaction has its status changed, PagSeguro will send a POST notification to the notify-url informed by the Merchant when a transaction was started.
The notification expects a HTTP Status 200 as response. In case such status is not returned, a new notification will be triggered after 10 minutes. Until a successful response is achieved.
Besides HTTP Status 200 as response, notifications of COMPLETE status expect that the Transaction Search API is accessed for the notified transaction. If a request is not made for such API, notifications will be triggered every 10 minutes as well.
Parameters are described below.

ParameterTypeDescription
transaction-codeRequiredStringTransaction code. It is the same as “transaction_id”
notification-typeRequiredStringSent with the literal value "transaction" for this status change notification flow
test-modeRequiredBooleanIndicates whether the transaction was created in sandbox environment
Please note that to receive our notifications, you should allowlist the following IPs:
  • 177.71.206.83
  • 54.233.76.62
  • 34.231.230.192
  • 34.232.159.3
This manual refers to the most recent version of status change notifications. You can contact our technical support team to activate it for your account if you have been integrated with a previous version. After that, both formats will be sent to your notification URL.

Example

POST http://your-virtual-store.com/transaction-notification/ HTTP/1.1
Host: boacompra.com
Content-Length:86
Content-Type: application/x-www-form-urlencoded
transaction-code=1234567890
notification-type=transaction
test-mode=false

Transactions Search API

Retrieve information about transactions.
The API can return information about one specific transaction or a list of transactions, based on the search criteria requested via API.

If the transactionCode is not sent, a date range search is mandatory. The maximum date range search is 30 days.

Host: https://api.boacompra.com/transactions/{transactionCode}

Method: GET

Input Parameters

ParameterTypeDescription
initial-order-dateOptionalTimestampInitial date, based when the order was created, to be searched. Only transactions created after the date sent in this parameter will be returned. If a transactionCode is not sent, a date range search is mandatory. Format: YYYY-MM-DDThh:mm:ss.sTZD Example: 2015-06-09T14:00:00.000-03:00
final-order-dateOptionalTimestampFinal date, based when the order was created, to be searched. Only transactions created before this date will be returned. If an initial-order-date is sent and the final-order-date is left in blank, the current date will be considered unless it is greater than 30 days. In this case, will be considered a 30-day search. If a final-order-date is sent, the parameter initial-order-date is required. Format: YYYY-MM-DDThh:mm:ss.sTZD Example: 2015-06-10T14:00:00.000-03:00
initial-payment-dateOptionalTimestampInitial date, based when the order was payed, to be searched. Only transactions payed after the date sent in this parameter will be returned. If a transactionCode is not sent, a date range search is mandatory. Format: YYYY-MM-DDThh:mm:ss.sTZD Example: 2015-06-09T14:00:00.000-03:00
final-payment-dateOptionalTimestampFinal date, based when the order was created, to be searched. Only transactions payed before this dates will be returned. If an initial-payment-date is sent and the final-payment-date is left in blank, the current date will be considered unless it is greater than 30 days. In this case, will be considered a 30-day search. If a final-payment-date is sent, the parameter initial-payment-date becomes required. Format: YYYY-MM-DDThh:mm:ss.sTZD **Example: 2015-06-10T14:00:00.000-03:00
initial-last-status-change-dateOptionalTimestampInitial date, based on the last status change, to be searched. Only transactions with changes on their status after the date sent in this parameter will be returned. If a transactionCode is not sent, a date range search is mandatory. Format: YYYY-MM-DDThh:mm:ss.sTZD
final-last-status-change-dateOptionalTimestampFinal date, based on the last status change, to be searched. Only transactions with changes on their status before this dates will be returned. If the initial-last-status-change-date is sent and the final-last-status-change-date is left in blank, the current date will be considered unless it is greater than 30 days. In this case, will be considered a 30-day search. If final-last-status-change-date is sent, the parameter initial-last-status-change-date becomes required. Format: YYYY-MM-DDThh:mm:ss.sTZD Example: 2015-06-10T14:00:00.000-03:00
statusOptionalStringTransactions status to be filtered. Values: CANCELLED, COMPLETE, CHARGEBACK, EXPIRED, NOT-PAID, PENDING, REFUNDED, UNDER-REVIEW
pageOptionalIntIf the search result is presented in more than one page, it’s possible to use this parameter to navigate among the pages.
max-page-resultsOptionalIntNumber of results per page. Default value and maximum accepted is 10.

In the sequence, a few examples of requests are available:

  1. https://api.boacompra.com/transactions/{transactionCode} - Returns the information of a specific transaction

  2. https://api.boacompra.com/transactions?initial-order-date=2015-06-10T14:00:00.000-03:00&final-order-date=2015-06-20T14:00:00.000-03:00 - Returns the first ten transactions created on the informed period

Success Response

The response contains metadata information with the number of transactions returned for the request and an array of transaction’s object with the information of each transaction.

HTTP Status Code: 200

Status Description

NameDescription
CANCELLEDTransaction was cancelled by PagSeguro
COMPLETETransaction was paid and approved. Products should be deliver to the End User
CHARGEBACKAn approved transaction was cancelled by the End User. Please consult your Account Manager for costs.
EXPIREDPayment date of transaction expired
NOT-PAIDPayment confirmation of transaction was not receive.
PENDINGTransaction was created
REFUNDEDA partial or full refund was requested and accepted for the transaction
UNDER-REVIEWTransaction is under review by PagSeguro Analysis team. It will be approved or cancelled based on the analysis.

JSON Response example:

{
    "transaction-result": {
        "store-id": "10",
        "transactions": [
            {
                "transaction-code": "87990145",
                "order-id": " 1500397602",
                "order-description": "Purchase Test",
                "status": "REFUNDED",
                "currency": "BRL",
                "amount": "10.00",
                "customer-email": "[email protected]",
                "customer-country": "BR",
                "notify-url": "https://loja_teste.international.pagseguro.com/consume_notifications.php",
                "payment-country": "BR",
                "payment-id": "3",
                "payment-name": "mastercard",
                "order-date": "2017-07-18T14:18:44-03:00",
                "payment-date": "2017-07-18T14:21:02-03:00",
                "last-status-change-date": "2017-07-18T14:30:10-03:00",
                "chargeback-date": null,
                "refundable": false,
                "refunds": [
                    {
                        "refund-id": "32926",
                        "refund-status": "PROCESSED",
                        "refund-amount": "10.00",
                        "refund-date": "2017-07-18T14:21:47-03:00",
                        "refund-processing-date": "2017-07-18T00:00:00-03:00",
                        "refund-reference": "BC-34134"
                    }
                ],
                "payment-methods": [
                    {
                        "code": "123E4567E89B12D3A456426655440000",
                        "date-created": "2018-04-11T11:31:11.571488493-03:00",
                        "credit-card": {
                            "brand": "visa",
                            "masked-number": "************0002",
                            "expiration-date": "2026-12"
                        }
                    }
                ],
                "payment-response": {
                    "code": 20000,
                    "message": "Success"
                }
            }
        ]
    },
    "metadata": {
        "found": "1",
        "page-results": 1,
        "current-page": 1,
        "total-pages": 1
    }
}

ParameterDescription
transactions-result Object
transaction-codePagSeguro unique identifier for the transaction
order-idMerchant unique identifier for the transaction
order-descriptionDescription provided by the Merchant when the checkout was created
statusTransaction status
currencyCurrency related to the amount of the transaction
amountAmount of the transaction
customer-mailCustomer e-mail used in PagSeguro checkout
customer-countryCountry in which the customer IP was tracked
notify-urlURL that PagSeguro notified the Merchant
payment-countryCountry where the payment was made
payment-idPagSeguro payment identifier (for more information, check the Integration Guide)
order-dateDate that the checkout was created
payment-dateDate that the customer paid the order
last-status-change-dateDate that the last status change occurred
chargeback-date DEPRECATED - Return is null
refunds Object
refund-idPagSeguro unique identifier for a refund
refund-statusStatus of the refund
refund-amountAmount to be refunded
refund-dateDate that the refund was requested
refund-processing-dateDate that the refund was paid
refund-referenceMerchant refund identifier
payment-methods Object
codeTokenized card code
date-createdTokenized card creation date
credit-cart Object
brandBrand of the credit cart
masked-numberThe last 4 number of the credit card
expiration-dateExpiration date of the credit cart
payment-response ObjectReturning only when the transaction is “BR”, with “CREDIT CARD” and status “NOT PAID”
codeCredit card rejection reason code
messageDetailed credit card reason code message

Error response

In case of errors in the request, expect a HTTP Status Code different from 200. The body response also contains an error object with the description and an error code, like the following example.
Error Code list here.

Response Body Example:

{
    "errors": [
        {
            "code": "17078",
            "description": "currency_not_accepted"
        }
    ]
}

Test Environment

PagSeguro provides a sandbox(test-mode) environment for testing purposes, to create a testing transaction simply send the request to the following endpoint api.sandbox.boacompra.com

For proper simulation of all status and integration flow, PagSeguro offers a panel.
Please access the following URL with credentials provided by your Account Manager.

Host: https://billing-partner.international.pagseguro.com

Search for your test transaction in the “Transactions test” menu:

172

Once you find it, please click on the “detail” icon:

696

You can select the status you want to simulate and send a notification by clicking in “Notify”:

Example

POST http://your-virtual-store.com/transaction-notification/ HTTP/1.1
Host: boacompra.com
Content-Length:86
Content-Type: application/x-www-form-urlencoded
transaction-code=1234567890
notification-type=transaction
test-mode=true
690

A notification will be sent to the URL defined in the notify_url integration field
along with the test-mode parameter.

Errors

Transaction Search API

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
22120id_invalidTransaction ID provided has an invalid format

Search Transaction and Notification

CodeKeyDescription
30101internal_server_errorError on Boa Compra servers