Problem with signature

Hi,

I’m trying to make my first API call - or second to first, as I don’t have any problems getting the countries list.

As soon as my httpbody isn’t empty, I’m getting UNAUTHENTICATED_API_CALL ,“message”:“Invalid signature”

I’m calling /v1/checkout

I’m using C# (4.7.2) and using Newtonsoft.Json to sterilize my request class, like this:

private static string SerializeBody(object from)
        {
            return  from != null ? JsonConvert.SerializeObject(
                    from,
                    Formatting.None,
                    new JsonSerializerSettings
                    {
                        NullValueHandling = NullValueHandling.Ignore,
                    }
                ) : string.Empty;
        }

Ending out with a string looking as this:

{“amount”:4130.00,“complete_payment_url”:“http://oneshop.local/da-DK/gateway/Retur/Ok/649687b8-3308-420c-a0ff-c0b71c87ec74",“cancel_checkout_url”:“http://oneshop.local/da-DK/Checkout/Status/649687b8-3308-420c-a0ff-c0b71c87ec74”,“country”:“DK”,“currency”:"DKK”}

I’m pretty sure its the body serialization that is the problem as I have tried to make the same call to /v1/checkout with an empty body, and then I’m getting a MISSING_FIELDS - [COUNTRY] error

Does anybody have a suggestion as to what I’m doing wrong with the http-body

I have found the problem, the amount is serialized with decimales when it’s an integer

When the amount is changed to 4130 the request is accepted.

2 Likes

Thank you @onesoft for posting your question and solution. :+1:

This was a fun challenge :unamused:

Here is my current solution for c#:

RoundedCurrencyAmount to hold the amount and take care of the rounding

public class RoundedCurrencyAmount
{
    private static readonly string[] _threeDigitsCurrencies = {"BHD", "IQD", "JOD", "KWD", "LYD", "OMR", "TND"};
    private static readonly string[] _fourDigitsCurrencies = { "CLF", "UYW"};

    private readonly decimal _amountTotal;

    public RoundedCurrencyAmount(decimal amountTotal, string currencyIsoCode)
    {
        CurrencyIsoCode = currencyIsoCode;
        _amountTotal = amountTotal;
    }

    public string CurrencyIsoCode { get; private set; }

    [Localizable(false)]
    public override string ToString()
    {
        if (_amountTotal % 1 == 0)
            return _amountTotal.ToString("F0", CultureInfo.InvariantCulture);

        if(_threeDigitsCurrencies.Contains(CurrencyIsoCode))
            return _amountTotal.ToString("F3", CultureInfo.InvariantCulture);

        if (_fourDigitsCurrencies.Contains(CurrencyIsoCode))
            return _amountTotal.ToString("F4", CultureInfo.InvariantCulture);

        return _amountTotal.ToString("F2", CultureInfo.InvariantCulture);
    }
}

The request class:

public class RapydCreateCheckoutPageRequest
{
    public RapydCreateCheckoutPageRequest(decimal amountTotal, string currencyCode)
    {
        Amount = new RoundedCurrencyAmount(amountTotal, currencyCode);
    }

    /// <summary>
    /// The amount of the payment, in units of the currency defined in currency. 
    /// Decimal, including the correct number of decimal places for the currency exponent, as defined in ISO 4217:2015. 
    /// If the amount is a whole number, use an integer and not a decimal
    /// </summary>
    [JsonProperty(@"amount")]
    public RoundedCurrencyAmount Amount { get; }
  ....
}

For serialization with newtonsoft:

class RoundedCurrencyAmountJsonConverter : JsonConverter
{
    public override bool CanRead => false;

    public override object ReadJson(
           JsonReader reader, 
           Type objectType, 
            object existingValue, 
            JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(RoundedCurrencyAmount);
    }

    public override void WriteJson(
                   JsonWriter writer, object value, JsonSerializer serializer)
    {
        var item = (RoundedCurrencyAmount)value;
        writer.WriteRawValue(item.ToString());
    }
}

and finally the updated sterilizeBody function:

private static string SerializeBody(object from)
{
    var s = from as string;
    if(s != null)
        return s;

    return from != null ? JsonConvert.SerializeObject(
            from,
            Formatting.None,
                
            new JsonSerializerSettings
            {
                Converters = new List<JsonConverter> { new RoundedCurrencyAmountJsonConverter()},
                NullValueHandling = NullValueHandling.Ignore,
            }
        ) : string.Empty;
    }
2 Likes