AliOz
AliOz

Reputation: 485

Creating an invoice through CyberSource APIs using the sandbox credentials is not working

I have created a Shared Secret Key for HTTP Signature Authentication here When I am trying to use them to process a payment in the CyberSource developers playground it works perfectly and in returns 200 OK response

However, when I am trying to create an invoice using the same credentials here, I always get the following 401 UnAuthorized

{
  "submitTimeUtc": "2023-05-25T06:07:10.578Z",
  "status": "UNAUTHORIZED",
  "reason": "Unauthorized",
  "message": "Unauthorized Request"
}

Why and how to solve this issue? Thanks in advance

Upvotes: 1

Views: 230

Answers (2)

Nik Patel
Nik Patel

Reputation: 354

I have created a service file that can help you, You can use them for the POST and GET both requests

<?php


class CyberSourceService
{
    public $request_host;
    public $merchant_id;
    public $merchant_key_id;
    public $merchant_secret_key;

    public function __construct()
    {
        $this->request_host = 'apitest.cybersource.com' // this is sendbox host
        $this->merchant_id = 'cyber_source.merchant_id'
        $this->merchant_key_id = 'cyber_source.api_key_id'
        $this->merchant_secret_key = 'cyber_source.secret_key'
    }

    protected function generateDigest($requestPayload)
    {
        $utf8EncodedString = mb_convert_encoding($requestPayload, "UTF-8");
        $digestEncode = hash("sha256", $utf8EncodedString, true);

        return base64_encode($digestEncode);
    }

    public function getHttpSignature($resourcePath, $httpMethod = "post", $payload = [])
    {
        $currentDate = date("D, d M Y G:i:s ") . "GMT";

        if ($httpMethod == "post") {
            $digest = $this->generateDigest($payload); // Get digest data

            $signatureString = "host: " . $this->request_host . "\ndate: " . $currentDate . "\n(request-target): " . $httpMethod . " " . $resourcePath . "\ndigest: SHA-256=" . $digest . "\nv-c-merchant-id: " . $this->merchant_id;
        } else {
            $signatureString = "host: " . $this->request_host . "\ndate: " . $currentDate . "\n(request-target): " . $httpMethod . " " . $resourcePath . "\nv-c-merchant-id: " . $this->merchant_id;
        }

        $signatureByteString = mb_convert_encoding($signatureString, "UTF-8");
        $decodeKey = base64_decode($this->merchant_secret_key);
        $signature = base64_encode(hash_hmac("sha256", $signatureByteString, $decodeKey, true));

        $signatureHeader = array(
            'keyid="' . $this->merchant_key_id . '"',
            'algorithm="HmacSHA256"'
        );

        if ($httpMethod == "post") {
            $signatureHeader = array_merge($signatureHeader, array('headers="host date (request-target) digest v-c-merchant-id"'));
            $signatureHeader = array_merge($signatureHeader, array('signature="' . $signature . '"'));
        } else {
            $signatureHeader = array_merge($signatureHeader, array('headers="host date (request-target) v-c-merchant-id"'));
            $signatureHeader = array_merge($signatureHeader, array('signature="' . $signature . '"'));
        }

        $headers = array(
            "Accept: application/hal+json;charset=utf-8",
            "Content-Type: application/json;charset=utf-8",
            "v-c-merchant-id: " . $this->merchant_id,
            "Signature: " . implode(", ", $signatureHeader),
            "Host: " . $this->request_host,
            "Date: " . $currentDate
        );

        if ($httpMethod == "post") {
            $headers = array_merge($headers, array("Digest: SHA-256=" . $digest));
        }

        return $headers;
    }

    public function request($resourcePath, $httpMethod = "post", $payLoad = [])
    {
        $payLoad = json_encode($payLoad);
        $headers = $this->getHttpSignature($resourcePath, $httpMethod, $payLoad);
        $url = "https://" . $this->request_host . $resourcePath;

        $curl = curl_init();

        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);

        if ($httpMethod == "post") {
            curl_setopt($curl, CURLOPT_POST, true);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $payLoad);
        }

        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HEADER, 1);
        curl_setopt($curl, CURLOPT_VERBOSE, 0);

        $response = curl_exec($curl);
        $http_header_size = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
        $http_body = json_decode(substr($response, $http_header_size), true);

        return $http_body ?? [];
    }
}

GET request

$transactionResponse = (new CyberSourceService())->request("/pts/v2/payments/$paymentID", "get");

POST request

 $paymentInformationCardArr = [
            "number" => 'card_number',
            "expirationMonth" => "expiry_month",
            "expirationYear" => "expiry_year",
            "securityCode" => "security_code",
            "type" =>  cardType code //https://developer.cybersource.com/library/documentation/dev_guides/Retail_SO_API/html/Topics/app_card_types.htm

$orderInformationAmountDetailsArr = [
    "totalAmount" => formatPrice($this->ticket->total),
    "currency" => "USD"
];
$orderInformationBillToArr = [
    "firstName" => first_name
    "lastName" => last_name
    "address1" => address1
    "address2" => address2
    "locality" => city
    "administrativeArea" => state
    "country" => country
    "postalCode" => postal_code
    "phoneNumber" => phone_number'
    "email" => $this->user->email,
];

$orderPayLoad = [
    "clientReferenceInformation" => [
        "code" => $this->ticket->booking_no
    ],
    "processingInformation" => [
        "commerceIndicator" => "internet",
        "capture" => true
    ],
    "orderInformation" => [
        "billTo" => $orderInformationBillToArr,
        "amountDetails" => $orderInformationAmountDetailsArr
    ],
    "paymentInformation" => [
        "card" => $paymentInformationCardArr
    ]
];
$this->orderResponse = (new CyberSourceService())->request("/pts/v2/payments", "post", $orderPayLoad);


Upvotes: 3

AliOz
AliOz

Reputation: 485

It turned out that you cannot create an invoice using Test Credentials, it has to be PROD credentials

Upvotes: 0

Related Questions