3.13. /api/v2/return
Introduction
ReturnΒ transactions may only be initiated when the transaction have final successful status. SeeΒ Statuses. ForΒ PreauthΒ it makesΒ CancelΒ transaction, forΒ CaptureΒ andΒ SaleΒ βΒ Reversal.Β ReturnΒ transactions are initiated throughΒ HTTPS POSTΒ request by usingΒ URLsΒ and theΒ parametersΒ specified below. UseΒ SHA-1Β for authentication.
API URLs
| Integration | Production |
|---|---|
| https://sandbox.billblend.com/checkout/api/v2/return/ENDPOINTID | https://pay.billblend.com/checkout/api/v2/return/ENDPOINTID |
| https://sandbox.billblend.com/checkout/api/v2/return/group/ENDPOINTGROUPID | https://pay.billblend.com/checkout/api/v2/return/group/ENDPOINTGROUPID |
Request Parameters
Note
Request must have content-type=application/x-www-form-urlencoded.
Warning
The following characters must be escaped in the parameter values: & + β.
| Parameter Name | Description | Value |
|---|---|---|
| login | Connecting Party login name. | Necessity: MandatoryType: StringLength: 20 |
| orderid | Unique order identifier assigned by Billblend system. | Necessity: MandatoryType: StringLength: 20 |
| client_orderid | Unique Connecting Party identifier. | Necessity: MandatoryType: StringLength: 128 |
| control | Checksum generated by SHA-1. Control string is represented as concatenation of the following parameters:1. Request parameter: login.2. Request parameter: client_orderid.3. Request parameter: orderid.4. Request parameter: amount (in minor units, if sent).5. Request parameter: currency (if sent).6. merchant_control (Control key assigned to Connecting Party account in the Billblend gateway system). | Necessity: ConditionalType: StringLength: 128 |
| amount | The amount has to be specified in the highest units with . delimiter. For instance, 10.5 for USD means 10 US Dollars and 50 Cents. If this parameter is omitted, initial transaction is reversed as a whole. Amount only makes sense for reversals, not cancels. Amount cannot exceed initial transaction amount. Please note that Currency MUST be specified if amount is specified! | Necessity: MandatoryType: NumericLength: 10 |
| currency | Currency in which amount is specified. Provided in three-letter currency code format. Example: USD for US Dollar. Reference:Β Currency Codes. | Necessity: MandatoryType: StringLength: 50 |
| comment | A brief description of reason. | Necessity: MandatoryType: StringLength: 50 |
Response Parameters
Note
Response has Content-Type: text/html;charset=utf-8 header. All fields are x-www-form-urlencoded, with (0xA) character at the end of each parameterβs value.
| Parameter Name | Description |
|---|---|
| type | The type of response. May be async-response, validation-error, error. If type equals validation-error or error, error-message and error-code parameters contain error details. |
| paynet-order-id | Order id assigned to the order by Billblend. |
| merchant-order-id | Connecting Party order id. |
| serial-number | Unique number assigned by Billblend server to particular request from the Connecting Party. |
| end-point-id | Entry point used for processing this transaction. |
| error-message | If status is error this parameter contains the reason for decline or error details. |
| error-code | The error code is case of error status. |
Request Example
POST /checkout/api/v2/return/39914 HTTP/1.1 Host: sandbox.billblend.com User-Agent: curl/7.83.0 Accept: */* Content-Length: 162 Content-Type: application/x-www-form-urlencoded Connection: close login=TestMerchant &client_orderid=Test &orderid=6862958 &amount=5.00 ¤cy=RUB &comment=Service not provided &control=2dfdb99c4eff5b31c978ecb8bc4b4d094e24c1d4
Success Response Example
HTTP/1.1 200 OK Server: server Date: Mon, 08 Aug 2022 07:50:08 GMT Content-Type: text/html;charset=utf-8 Connection: close Vary: Accept-Encoding X-XSS-Protection: 1 X-Content-Type-Options: nosniff Strict-Transport-Security: max-age=31536000 Content-Language: en-US Strict-Transport-Security: max-age=31536000 Content-Length: 141 type=async-response &serial-number=00000000-0000-0000-0000-000002ddad4a &merchant-order-id=Test &paynet-order-id=6862958 &end-point-id=39914
Fail Response Example
HTTP/1.1 200 OK Server: server Date: Mon, 08 Aug 2022 10:45:32 GMT Content-Type: text/html;charset=utf-8 Connection: close Vary: Accept-Encoding X-XSS-Protection: 1 X-Content-Type-Options: nosniff Strict-Transport-Security: max-age=31536000 Content-Language: en-US Strict-Transport-Security: max-age=31536000 Content-Length: 153 type=validation-error &serial-number=00000000-0000-0000-0000-000002ddad5c &error-message=Reversal+currency+does+not+match+project+currency &error-code=16
Postman Collection
Postman Collection is available at this link – https://doc.billblend.com/integration/API_commands/api_v2_return.html#postman-collection
Request Builder
Request Builder is available at this link –Β https://doc.billblend.com/integration/API_commands/api_v2_return.html#request-builder
| endpointid or groupid | input ENDPOINTID or ENDPOINTGROUPID |
|---|---|
| login | |
| client_orderid | input Invoice Number |
| orderid | |
| amount | |
| currency | |
| merchant_control | input Control Key |
| comment |
curl --data "login=logic&client_orderid=902B4FF5&orderid=159884&amount=5.00¤cy=EUR&comment=Service not provided&control=f9fcfd80c03a9ad9d813f67f11095512be4feffb" https://sandbox.billblend.com/checkout/api/v2/return/1<?php
/**
* Executes request
*
* @param string $url Url for payment method
* @param array $requestFields Request data fields
*
* @return array Host response fields
*
* @throws RuntimeException Error while executing request
*/
function sendRequest($url, array $requestFields)
{
$curl = curl_init($url);
curl_setopt_array($curl, array
(
CURLOPT_HEADER => 0,
CURLOPT_USERAGENT => 'Billblend-Client/1.0',
CURLOPT_SSL_VERIFYHOST => 0,
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_POST => 1,
CURLOPT_RETURNTRANSFER => 1
));
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($requestFields));
$response = curl_exec($curl);
if(curl_errno($curl))
{
$error_message = 'Error occurred: ' . curl_error($curl);
$error_code = curl_errno($curl);
}
elseif(curl_getinfo($curl, CURLINFO_HTTP_CODE) != 200)
{
$error_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$error_message = "Error occurred. HTTP code: '{$error_code}'";
}
curl_close($curl);
if (!empty($error_message))
{
throw new RuntimeException($error_message, $error_code);
}
if(empty($response))
{
throw new RuntimeException('Host response is empty');
}
$responseFields = array();
parse_str($response, $responseFields);
return $responseFields;
}
function signString($s, $merchantControl)
{
return sha1($s . $merchantControl);
}
/**
* Signs payment (sale/auth/transfer) request
*
* @param array $requestFields request array
* @param string $endpointOrGroupId endpoint or endpoint group ID
* @param string $merchantControl merchant control key
*/
function signPaymentRequest($requestFields, $endpointOrGroupId, $merchantControl)
{
$base = '';
$base .= $endpointOrGroupId;
$base .= $requestFields['client_orderid'];
$base .= $requestFields['amount'] * 100;
$base .= $requestFields['email'];
return signString($base, $merchantControl);
}
/**
* Signs status request
*
* @param array $requestFields request array
* @param string $login merchant login
* @param string $merchantControl merchant control key
*/
function signStatusRequest($requestFields, $login, $merchantControl)
{
$base = '';
$base .= $login;
$base .= $requestFields['client_orderid'];
$base .= $requestFields['orderid'];
return signString($base, $merchantControl);
}
function signAccountVerificationRequest($requestFields, $endpointOrGroupId, $merchantControl)
{
$base = '';
$base .= $endpointOrGroupId;
$base .= $requestFields['client_orderid'];
$base .= $requestFields['email'];
return signString($base, $merchantControl);
}
$endpointId = 1;
$merchantControl = 'B17F59B4-A7DC-41B4-8FF9-37D986B43D20';
$requestFields = array(
'login' => 'logic',
'client_orderid' => '902B4FF5',
'orderid' => '159884',
'amount' => '5.00',
'currency' => 'EUR',
'comment' => 'Service not provided',
);
$requestFields['control'] = signPaymentRequest($requestFields, $endpointId, $merchantControl);
$responseFields = sendRequest('https://sandbox.billblend.com/checkout/api/v2/return/1', $requestFields);
print_r($responseFields);
?>require 'net/http'
require 'uri'
require 'cgi'
require 'digest/sha1'
##
# Executes request
#
# @param url [String] Url for payment method
# @param request_fields [Hash] Request data fields
#
# @return [Hash] Host response fields
def send_request(url, request_fields)
begin
uri = URI url
response = Net::HTTP.start uri.hostname, uri.port, :use_ssl => uri.scheme == 'https' do |http|
post = Net::HTTP::Post.new uri.request_uri
post.set_form_data request_fields
http.request post
end
rescue Exception => e
raise RuntimeError, "Error occurred. #{e.message}"
end
unless Net::HTTPOK === response
raise RuntimeError, "Error occurred. HTTP code: '#{response.code}'. Server message: '#{response.message}'"
end
unless response.body
raise RuntimeError, 'Host response is empty'
end
# Change hash format from {'key' => ['value']} to {'key' => 'value'} in map block
Hash[CGI.parse(response.body).map {|key, value| [key, value.first]}]
end
def sign_string(str, merchant_control)
Digest::SHA1.hexdigest(str + merchant_control)
end
def sign_payment_request(request_fields, endpoint_or_group_id, merchant_control)
base = ''
base += endpoint_or_group_id
base += request_fields['client_orderid']
base += (request_fields['amount'].to_f * 100).to_i
base += request_fields['email']
sign_string(base, merchant_control)
end
def sign_status_request(request_fields, login, merchant_control)
base = ''
base += login
base += request_fields['client_orderid']
base += request_fields['orderid'].nil? ? '' : request_fields['orderid']
sign_string(base, merchant_control)
end
request_fields = {
'login' => 'logic',
'client_orderid' => '902B4FF5',
'orderid' => '159884',
'amount' => '5.00',
'currency' => 'EUR',
'comment' => 'Service not provided',
'control' => 'f9fcfd80c03a9ad9d813f67f11095512be4feffb'
};
response_fields = send_request('https://sandbox.billblend.com/checkout/api/v2/return/1', request_fields);
require 'pp'
pp response_fields
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class Main {
//Transactions are initiated by using URL in the following format: /checkout/api/v2/TRANSACTION_TYPE/ENDPOINTID or /checkout/api/v2/TRANSACTION_TYPE/ENDPOINTGROUPID (if group is supported)
//Use "gate" for production purposes or "sandbox" for integration needs
private static String targetURL = "https://sandbox.billblend.com/checkout/api/v2/return/1";
//Request parameters
private static String urlParameters = "login=logic&client_orderid=902B4FF5&orderid=159884&amount=5.00¤cy=EUR&comment=Service not provided&";
//String for calculating control code parameter
private static String controlParameters = "logic902B4FF5159884500EURB17F59B4-A7DC-41B4-8FF9-37D986B43D20";
public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
//Sending POST request to the specified URL with request parameters and SHA1-encrypted control parameter
System.out.println(executePost(targetURL, urlParameters + "control= " + sha1(controlParameters)));
}
static String sha1(String input) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest mDigest = MessageDigest.getInstance("SHA1");
byte[] result = mDigest.digest(input.getBytes("utf-8"));
StringBuffer sb = new StringBuffer();
for (int i = 0; i < result.length; i++) {
sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
public static String executePost(String targetURL, String urlParameters)
{
URL url;
HttpURLConnection connection = null;
try {
//Create connection
url = new URL(targetURL);
connection = (HttpURLConnection)url.openConnection();
connection.setDoOutput(true);
//Send request
DataOutputStream wr = new DataOutputStream (
connection.getOutputStream ());
wr.writeBytes (urlParameters);
wr.flush ();
wr.close ();
//Get Response
InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer response = new StringBuffer();
while((line = rd.readLine()) != null) {
response.append(line);
response.append('\n');
}
rd.close();
return response.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if(connection != null) {
connection.disconnect();
}
}
}
}