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
How it Works
UOL BoaCompra notifies Merchant that a transaction status has changed
Merchant requests the transaction information provided in the notification to UOL BoaCompra
UOL BoaCompra responds back with the transaction information
Transaction Search API
Merchant requests transaction information
UOL BoaCompra 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:
Parameter | Description |
---|---|
Accept | This parameter informs the API version, data format (JSON) and encoding. Default value is: application/vnd.boacompra.com.v1+json; charset=UTF-8 |
Accept-Language | Input language. Default value is en-US. |
Authorization | To create a request the following information is required: store-id¹, secret-key¹, HTTP-Verb (url path + query string) and Content-MD5. |
Content-Type | application/json |
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, UOL BoaCompra 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.
Parameter | Type | Description | |
---|---|---|---|
transaction-code | Required | String | Transaction code. It is the same as “transaction_id” |
notification-type | Required | String | Value: transaction |
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
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.
Host: https://api.boacompra.com/transactions/{transactionCode}
Method: GET
Input Parameters
Parameter | Type | Description | |
---|---|---|---|
initial-order-date | Optional | Timestamp | Initial 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-date | Optional | Timestamp | Final 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-date | Optional | Timestamp | Initial 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-date | Optional | Timestamp | Final 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-date | Optional | Timestamp | Initial 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-date | Optional | Timestamp | Final 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 |
status | Optional | String | Transactions status to be filtered. Values: CANCELLED , COMPLETE , CHARGEBACK , EXPIRED , NOT-PAID , PENDING , REFUNDED , UNDER-REVIEW |
page | Optional | Int | If the search result is presented in more than one page, it’s possible to use this parameter to navigate among the pages. |
max-page-results | Optional | Int | Number of results per page. Default value and maximum accepted is 10. |
In the sequence, a few examples of requests are available:
https://api.boacompra.com/transactions/{transactionCode}
- Returns the information of a specific transactionhttps://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
Name | Description |
---|---|
CANCELLED | Transaction was cancelled by UOL BoaCompra |
COMPLETE | Transaction was paid and approved. Products should be deliver to the End User |
CHARGEBACK | An approved transaction was cancelled by the End User. Please consult your Account Manager for costs. |
EXPIRED | Payment date of transaction expired |
NOT-PAID | Payment confirmation of transaction was not receive. |
PENDING | Transaction was created |
REFUNDED | A partial or full refund was requested and accepted for the transaction |
UNDER-REVIEW | Transaction is under review by UOL BoaCompra 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": "test@boacompra.com",
"customer-country": "BR",
"notify-url": "https://loja_teste.boacompra.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"
}
}
]
}
]
},
"metadata": {
"found": "1",
"page-results": 1,
"current-page": 1,
"total-pages": 1
}
}
Parameter | Description |
---|---|
transactions-result Object | |
transaction-code | BoaCompra unique identifier for the transaction |
order-id | Merchant unique identifier for the transaction |
order-description | Description provided by the Merchant when the checkout was created |
status | Transaction status |
currency | Currency related to the amount of the transaction |
amount | Amount of the transaction |
customer-mail | Customer e-mail used in BoaCompra checkout |
customer-country | Country in which the customer IP was tracked |
notify-url | URL that BoaCompra notified the Merchant |
payment-country | Country where the payment was made |
payment-id | BoaCompra payment identifier (for more information, check the Integration Guide) |
order-date | Date that the checkout was created |
payment-date | Date that the customer paid the order |
last-status-change-date | Date that the last status change occurred |
chargeback-date | DEPRECATED - Return is null |
refunds Object | |
refund-id | BoaCompra unique identifier for a refund |
refund-status | Status of the refund |
refund-amount | Amount to be refunded |
refund-date | Date that the refund was requested |
refund-processing-date | Date that the refund was paid |
refund-reference | Merchant refund identifier |
payment-methods Object | |
code | Tokenized card code |
date-created | Tokenized card creation date |
credit-cart Object | |
brand | Brand of the credit cart |
masked-number | The last 4 number of the credit card |
expiration-date | Expiration date of the credit cart |
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
BoaCompra 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, UOL BoaCompra offers a panel. Please access the following URL with credentials provided by your Account Manager.
Host: https://billing-partner.boacompra.com
Search for your test transaction in the “Transactions test” menu:
Once you find it, please click on the “detail” icon:
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
A notification will be sent to the URL defined in the notify_url integration field along with the test-mode parameter.
Errors
Headers
Authorization Header
Code | Key | Description |
---|---|---|
10001 | header_authorization_missing | Missing header Authorization in request |
10002 | header_authorization_bad_format | Authorization header bad formation |
10003 | header_authorization_invalid | Authorization header error |
Accept Header
Code | Key | Description |
---|---|---|
10201 | header_accept_missing | Missing header Accept in request |
10202 | header_accept_application_missing | Missing Application on header Accept |
10203 | header_accept_bad_format | Header Accept with bad format |
10204 | header_accept_format_missing | Missing Format on header Accept |
10205 | header_accept_charset_missing | Missing Charset on header Accept |
10206 | header_accept_application_invalid | Invalid Application on Accept Header |
10207 | header_accept_format_invalid | Invalid Format on Accept Header |
10208 | header_accept_charset_invalid | Invalid Charset on Accept Header |
10209 | header_accept_version_invalid | Invalid Version on Accept Header |
Content-Type Header
Code | Key | Description |
---|---|---|
10301 | header_contenttype_missing | Missing header Content-Type in request |
10302 | header_contenttype_not_accepted | Content-Type is not accepted |
Accept Language
Code | Key | Description |
---|---|---|
10401 | header_language_not_accepted | Language not accepted |
Transaction Search API
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 |
22120 | id_invalid | Transaction ID provided has an invalid format |
Search Transaction and Notification
Code | Key | Description |
---|---|---|
30101 | internal_server_error | Error on Boa Compra servers |