private async Task <ClientResponse> _sendRequestAsync(string url, Request request, string traceNumber = null)
        {
            if (_cache != null && !string.IsNullOrEmpty(traceNumber))
            {
                var previousResponse = _cache.GetValue(traceNumber);
                if (!string.IsNullOrEmpty(previousResponse))
                {
                    return(_contentToClientResponse(previousResponse, traceNumber, true));
                }
            }
            var headers = new Headers(traceNumber, _options.InterfaceVersion, _options.Credentials.MerchantId);

            if (string.IsNullOrEmpty(headers.TraceNumber))
            {
                var newTrace = Guid.NewGuid().GetHashCode();
                if (newTrace < 0)
                {
                    newTrace = newTrace * -1;
                }
                headers.TraceNumber = newTrace.ToString();
            }

            var contentType = headers.ContentType();
            var client      = new HttpClient();

            client.BaseAddress = new Uri(url);
            client.DefaultRequestHeaders.Clear();
            client.DefaultRequestHeaders.Add("MIME-Version", headers.MIME_Version);
            client.DefaultRequestHeaders.Add("Content-transfer-encoding", headers.ContentTransferEncoding);
            client.DefaultRequestHeaders.Add("Request-number", headers.RequestNumber);
            client.DefaultRequestHeaders.Add("Document-type", headers.DocumentType);
            client.DefaultRequestHeaders.Add("Trace-number", headers.TraceNumber);
            client.DefaultRequestHeaders.Add("Interface-version", headers.InterfaceVersion);
            client.DefaultRequestHeaders.Add("MerchantID", headers.MerchantID);

            string body;
            var    requestSerializer = new XmlSerializer(typeof(Request));

            using (var stream = new MemoryStream())
                using (var writer = new StreamWriter(stream))
                {
                    var ns = new XmlSerializerNamespaces();
                    ns.Add("", "");
                    requestSerializer.Serialize(writer, request, ns);

                    stream.Position = 0;
                    using (var reader = new StreamReader(stream))
                    {
                        body = reader.ReadToEnd();
                    }
                }

            var httpRequest = new HttpRequestMessage(HttpMethod.Post, "");

            httpRequest.Content = new StringContent(body);
            httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
            var httpResponse = await client.SendAsync(httpRequest);

            var httpResponseContent = await httpResponse.Content.ReadAsStringAsync();

            if (httpResponse.IsSuccessStatusCode)
            {
                var clientResponse = _contentToClientResponse(httpResponseContent, traceNumber);

                var itemType = ResponseTypes.Types[clientResponse.Response.Item.GetType()];

                string procStatus = null;
                switch (itemType)
                {
                case (int)ResponeTypeIds.AccountUpdaterResp:
                    var accountUpdater = (accountUpdaterRespType)clientResponse.Response.Item;
                    procStatus = accountUpdater.ProfileProcStatus;
                    break;

                case (int)ResponeTypeIds.EndOfDayResp:
                    var endOfDay = (endOfDayRespType)clientResponse.Response.Item;
                    procStatus = endOfDay.ProcStatus;
                    break;

                case (int)ResponeTypeIds.FlexCacheResp:
                    var flexCache = (flexCacheRespType)clientResponse.Response.Item;
                    procStatus = flexCache.ProcStatus;
                    break;

                case (int)ResponeTypeIds.InquiryResp:
                    var inquiry = (inquiryRespType)clientResponse.Response.Item;
                    procStatus = inquiry.ProcStatus;
                    break;

                case (int)ResponeTypeIds.MarkForCaptureResp:
                    var markForCapture = (markForCaptureRespType)clientResponse.Response.Item;
                    procStatus = markForCapture.ProcStatus;
                    break;

                case (int)ResponeTypeIds.NewOrderResp:
                    var newOrder = (newOrderRespType)clientResponse.Response.Item;
                    procStatus = newOrder.ProcStatus;
                    break;

                case (int)ResponeTypeIds.ProfileResp:
                    var profile = (profileRespType)clientResponse.Response.Item;
                    procStatus = profile.ProfileProcStatus;
                    break;

                case (int)ResponeTypeIds.QuickResp:
                    var quick = (quickRespType)clientResponse.Response.Item;
                    procStatus = quick.ProcStatus;
                    break;

                case (int)ResponeTypeIds.QuickResponse:
                    var quick_old = (quickRespType_old)clientResponse.Response.Item;
                    procStatus = quick_old.ProcStatus;
                    break;

                case (int)ResponeTypeIds.ReversalResp:
                    var reversal = (reversalRespType)clientResponse.Response.Item;
                    procStatus = reversal.ProcStatus;
                    break;

                case (int)ResponeTypeIds.SafetechFraudAnalysisResp:
                    var safetechFraudAnalysis = (safetechFraudAnalysisRespType)clientResponse.Response.Item;
                    procStatus = safetechFraudAnalysis.ProcStatus;
                    break;

                default:
                    break;
                }

                if (procStatus?.Trim() != "0" && procStatus?.Trim() != "00")
                {
                    throw new Exception($"Request was unsuccesful - response was {httpResponseContent}");
                }
                if (!string.IsNullOrEmpty(traceNumber))
                {
                    _cache.SetValue(traceNumber, httpResponseContent);
                }

                return(clientResponse);
            }
            else
            {
                throw new Exception($"Unsuccesful communication with Chase with response {httpResponseContent}");
            }
        }
        async Task <ClientResponse> SendRequestAsync(string url, ClientRequest clientRequest)
        {
            if (string.IsNullOrEmpty(clientRequest.TraceNumber))
            {
                clientRequest.TraceNumber = NewTraceNumber();
            }
            else
            {
                if (!long.TryParse(clientRequest.TraceNumber, out long traceNumberVal))
                {
                    throw new Exception("Trace number must convert to int64");
                }
                if (traceNumberVal > MaxTraceNumber)
                {
                    throw new Exception("Trace number larger then accepted maximum");
                }
                if (_cache != null)
                {
                    var previousResponseContent = _cache.GetValue(clientRequest.TraceNumber);
                    if (!string.IsNullOrEmpty(previousResponseContent))
                    {
                        var previousClientResponse = ContentToClientResponse(previousResponseContent, clientRequest.TraceNumber, true);
                        return(previousClientResponse);
                    }
                }
            }

            var headers = new Headers(clientRequest.TraceNumber, InterfaceVersion, Credentials.MerchantId);

            var contentType = headers.ContentType();

            using var client = new HttpClient
                  {
                      BaseAddress = new Uri(url)
                  };
            client.DefaultRequestHeaders.Clear();
            client.DefaultRequestHeaders.Add("MIME-Version", headers.MIME_Version);
            client.DefaultRequestHeaders.Add("Content-transfer-encoding", headers.ContentTransferEncoding);
            client.DefaultRequestHeaders.Add("Request-number", headers.RequestNumber);
            client.DefaultRequestHeaders.Add("Document-type", headers.DocumentType);
            client.DefaultRequestHeaders.Add("Trace-number", headers.TraceNumber);
            client.DefaultRequestHeaders.Add("Interface-version", headers.InterfaceVersion);
            client.DefaultRequestHeaders.Add("MerchantID", headers.MerchantID);

            var scrubbedRequest        = ScrubClientRequest(clientRequest);
            var scrubbedRequestContent = ClientRequestToContent(scrubbedRequest);

            var requestBody = ClientRequestToContent(clientRequest);
            var httpRequest = new HttpRequestMessage(HttpMethod.Post, "")
            {
                Content = new StringContent(requestBody)
            };

            httpRequest.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
            var httpResponse = await client.SendAsync(httpRequest);

            var httpResponseContent = await httpResponse.Content.ReadAsStringAsync();

            if (string.IsNullOrEmpty(httpResponseContent))
            {
                throw new Exception("Response content is empty");
            }

            var clientResponse = ContentToClientResponse(httpResponseContent, clientRequest.TraceNumber);

            var scrubbedResponse        = ScrubClientResponse(clientResponse);
            var scrubbedResponseContent = ClientResponseToContent(scrubbedResponse);

            if (_cache != null)
            {
                _cache.SetValue(clientRequest.TraceNumber, scrubbedResponseContent);
            }

            var itemType = ResponseTypes.Types[clientResponse.Response.Item.GetType()];

            string procStatus = null;

            switch (itemType)
            {
            case (int)ResponeTypeIds.AccountUpdaterResp:
                var accountUpdater = (accountUpdaterRespType)clientResponse.Response.Item;
                procStatus = accountUpdater.ProfileProcStatus;
                break;

            case (int)ResponeTypeIds.EndOfDayResp:
                var endOfDay = (endOfDayRespType)clientResponse.Response.Item;
                procStatus = endOfDay.ProcStatus;
                break;

            case (int)ResponeTypeIds.FlexCacheResp:
                var flexCache = (flexCacheRespType)clientResponse.Response.Item;
                procStatus = flexCache.ProcStatus;
                break;

            case (int)ResponeTypeIds.InquiryResp:
                var inquiry = (inquiryRespType)clientResponse.Response.Item;
                procStatus = inquiry.ProcStatus;
                break;

            case (int)ResponeTypeIds.MarkForCaptureResp:
                var markForCapture = (markForCaptureRespType)clientResponse.Response.Item;
                procStatus = markForCapture.ProcStatus;
                break;

            case (int)ResponeTypeIds.NewOrderResp:
                var newOrder = (newOrderRespType)clientResponse.Response.Item;
                procStatus = newOrder.ProcStatus;
                break;

            case (int)ResponeTypeIds.ProfileResp:
                var profile = (profileRespType)clientResponse.Response.Item;
                procStatus = profile.ProfileProcStatus;
                break;

            case (int)ResponeTypeIds.QuickResp:
                var quick = (quickRespType)clientResponse.Response.Item;
                procStatus = quick.ProcStatus;
                break;

            case (int)ResponeTypeIds.QuickResponse:
                var quick_old = (quickRespType_old)clientResponse.Response.Item;
                procStatus = quick_old.ProcStatus;
                break;

            case (int)ResponeTypeIds.ReversalResp:
                var reversal = (reversalRespType)clientResponse.Response.Item;
                procStatus = reversal.ProcStatus;
                break;

            case (int)ResponeTypeIds.SafetechFraudAnalysisResp:
                var safetechFraudAnalysis = (safetechFraudAnalysisRespType)clientResponse.Response.Item;
                procStatus = safetechFraudAnalysis.ProcStatus;
                break;

            default:
                break;
            }
            if (_logger != null)
            {
                if (procStatus != "0")
                {
                    _logger.LogWarning("{Library} {MethodCall} {TraceNumber} {ScrubbedContent}", "PaymentechCore", "Request", clientRequest.TraceNumber, scrubbedRequestContent);
                    _logger.LogWarning("{Library} {MethodCall} {TraceNumber} {ScrubbedContent}", "PaymentechCore", "Response", clientRequest.TraceNumber, scrubbedResponseContent);
                }
                else
                {
                    _logger.LogInformation("{Library} {MethodCall} {TraceNumber} {ScrubbedContent}", "PaymentechCore", "Request", clientRequest.TraceNumber, scrubbedRequestContent);
                    _logger.LogInformation("{Library} {MethodCall} {TraceNumber} {ScrubbedContent}", "PaymentechCore", "Response", clientRequest.TraceNumber, scrubbedResponseContent);
                }
            }
            clientResponse.ProcStatus = procStatus;

            return(clientResponse);
        }