cancel
Showing results for 
Search instead for 
Did you mean: 

Unified Checkout: Capture Context API 400 Bad Request

Hello,

We are looking to build an integration using Unified Checkout with C# .NET. We have hit a bit of snag with the CaptureContext. When we make a request to the CaptureContext API we are receiving a 400 Bad Request response. We can't identify which parameters are incorrect. We believe that we are constructing, encrypting and signing the payload correctly? Please see example of our C# code below:

Any help at all is very much appreciated as we cannot move forwards until we can figure out this step and receive our capturecontext token

 

//Here is our Controller which makes the request to captureContext
[HttpPost]
    [Route("getcapturecontext")]
    public async Task<string> GetCaptureContextAsync()
    {
        var jwt = CreateJWT();
        var apiKey = ApiKey;
        var apiSecret = ApiSecret;
        var date = DateTime.UtcNow.ToString("R");

        var signature = GenerateSignature(jwt, apiKey, apiSecret, date);

        // Set the headers and request body
        using (var client = new HttpClient())
        {
            var signatureHeader = $"keyid=\"{apiKey}\", algorithm=\"HmacSHA256\", signature=\"{signature}\"";
            client.DefaultRequestHeaders.Add("v-c-merchant-id", "cmw50sandbox_1719243295");
            client.DefaultRequestHeaders.Add("date", date);
            client.DefaultRequestHeaders.Add("signature", signatureHeader);

            var requestContent = new StringContent(jwt, Encoding.UTF8, "application/jwt");

            // Send the request to CaptureContext
            var response = await client.PostAsync("https://apitest.cybersource.com/up/v1/capture-contexts", requestContent);
            var responseContent = response.Content;
            return await response.Content.ReadAsStringAsync();
        }        
    }
   
    //Create the JWT with sample payload and Base64 encoding
    private string CreateJWT()
    {
        var header = new { alg = "HS256", typ = "JWT" };

        var payload = new
        {
            targetOrigins = new List<string> { "https://yourCheckoutPage.com" },
            clientVersion = "0.19",
            allowedCardNetworks = new List<string> { "VISA", "MASTERCARD", "AMEX" },
            allowedPaymentTypes = new List<string> { "PANENTRY", "SRC", "GOOGLEPAY" },
            country = "IE",
            locale = "en_IE",
            captureMandate = new
            {
                billingType = "PARTIAL",
                requestEmail = false,
                requestPhone = false,
                requestShipping = false,
                showAcceptedNetworkIcons = true
            },
            orderInformation = new
            {
                amountDetails = new
                {
                    totalAmount = "21.00",
                    currency = "EUR"
                }
            }
        };

        var headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header));
        var payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload));

        var headerBase64 = Base64UrlEncode(headerBytes);
        var payloadBase64 = Base64UrlEncode(payloadBytes);

        return $"{headerBase64}.{payloadBase64}";
    }
    
    //Base64 encoding service for header and payload
    private string Base64UrlEncode(byte[] input)
    {
        var base64 = Convert.ToBase64String(input);
        return base64.Replace("+", "-").Replace("/", "_").TrimEnd('=');
    }

    //Sign the data using secret key. SignData encodes data using HmacSha256 encryption
    private string GenerateSignature(string jwt, string apiKey, string apiSecret, string date)
    {
        var dataToSign = $"date: {date}\n" +
                         $"digest: SHA-256={ComputeSha256Hash(jwt)}\n" +
                         $"v-c-merchant-id: cmw50sandbox_1719243295";

        return SignData(dataToSign, apiSecret);
    }

    private string ComputeSha256Hash(string rawData)
    {
        using (SHA256 sha256Hash = SHA256.Create())
        {
            var bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));
            return Convert.ToBase64String(bytes);
        }
    }

    private string SignData(string data, string key)
    {
        var keyBytes = Convert.FromBase64String(key);
        using (var hmacsha256 = new HMACSHA256(keyBytes))
        {
            var messageBytes = Encoding.UTF8.GetBytes(data);
            var hashMessage = hmacsha256.ComputeHash(messageBytes);
            return Convert.ToBase64String(hashMessage);
        }
    }

 

Can anyone provide assistance or feedback to help us move forwards with our integration. We are not sure how to move forwards.
Here is the response we receive back from the CaptureContext API

"{\"response\":{\"rmsg\":\"Bad Request\"}}"
 
Any assistance is greatly appreciated
 
Many thanks,
Tim Murray
CustomerMinds



customerminds
Member
1 REPLY 1

Would just like to provide an update on this. Wish to say thank you to Justin from Cybersource support for the help with this one.

If anyone encounters the same issue please follow these steps.

1. There is no need to encode the request body as a JWT. A standard JSON body is all that's required.

2. You still need to send your merchant-id, api key and secret as part of the request for authentication.

3. The response back to will be in JWT format.

 

We found these sources very helpful for us to generate the Capture Context JWT successfully.

https://github.com/CyberSource/cybersource-rest-samples-csharp/tree/46b7872a3e1493177b5b178946aadae6...
The specific sample for generating the Capture Context can be found here:
https://github.com/CyberSource/cybersource-rest-samples-csharp/blob/46b7872a3e1493177b5b178946aadae6...

customerminds
Member