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 – ReversalReturn transactions are initiated through HTTPS POST request by using URLs and the parameters specified below. Use SHA-1 for authentication.

API URLs

IntegrationProduction
https://sandbox.billblend.com/checkout/api/v2/return/ENDPOINTIDhttps://pay.billblend.com/checkout/api/v2/return/ENDPOINTID
https://sandbox.billblend.com/checkout/api/v2/return/group/ENDPOINTGROUPIDhttps://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 NameDescriptionValue
loginConnecting Party login name.Necessity: MandatoryType: StringLength: 20
orderidUnique order identifier assigned by Billblend system.Necessity: MandatoryType: StringLength: 20
client_orderidUnique Connecting Party identifier.Necessity: MandatoryType: StringLength: 128
controlChecksum 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
amountThe 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
currencyCurrency in which amount is specified. Provided in three-letter currency code format. Example: USD for US Dollar. Reference: Currency Codes.Necessity: MandatoryType: StringLength: 50
commentA 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 NameDescription
typeThe type of response. May be async-responsevalidation-errorerror. If type equals validation-error or errorerror-message and error-code parameters contain error details.
paynet-order-idOrder id assigned to the order by Billblend.
merchant-order-idConnecting Party order id.
serial-numberUnique number assigned by Billblend server to particular request from the Connecting Party.
end-point-idEntry point used for processing this transaction.
error-messageIf status is error this parameter contains the reason for decline or error details.
error-codeThe 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
&currency=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 groupidinput ENDPOINTID or ENDPOINTGROUPID
login
client_orderidinput Invoice Number
orderid
amount
currency
merchant_controlinput Control Key
comment
curl --data "login=logic&client_orderid=902B4FF5&orderid=159884&amount=5.00&currency=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&currency=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();
            }
        }
    }
}

Contact us

By clicking on the button, you agree to the data protection policy

Complete the quiz

By clicking on the button, you agree to the data protection policy