/// <summary>
        /// This report provides detailed information about transactions that were flagged by CyberSource or by the processor because of errors in requests for follow-on transactions. 
        /// When these errors occur, you are notified in the Message Center. These notifications remain in the Message Center for seven days. 
        /// The following figures show the Message Center and descriptions of transaction errors.
        /// </summary>
        /// <param name="qo">The filters in which to search for the report</param>
        /// <returns></returns>
        public static string GetTransactionExceptionDetails(CybersourceAPI.QueryObject.TransactionExceptionDetailQO qo)
        {
            // The report can not have a start and end date bigger than 24 hours
            // Expires differences. This is ridiculous... c'mon microsoft did you really need to make it this hard
            int secondsDifference = 0;
            TimeSpan timeDifference = qo.EndDateAndTime.Subtract(qo.StartDateAndTime);

            if (timeDifference.TotalHours > 24) {
                throw new Exception("The transaction Exception Detail report can only be run for 24 hours. The time span in hours is " + timeDifference.TotalHours);
            }

            // Single transaction URL
            string url = string.Format("https://ebc.cybersource.com/ebc/TransactionExceptionDetailReportRequest.do");
            return Call(url, qo);
        }
        protected static string Call(string url, CybersourceAPI.QueryObject.BaseQO qo)
        {
            string returnXML = null;

            try {

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                // Set the content type of the data being posted.
                request.ContentType = "application/x-www-form-urlencoded";
                request.Method = "POST";

                request.Headers.Add("Authorization", "Basic " + EncodeTo64(string.Format("{0}:{1}", qo.Username, qo.Password)));

                byte[] byteArray = Encoding.UTF8.GetBytes(qo.FormEncode());
                request.ContentLength = byteArray.Length;

                using (var input = request.GetRequestStream()) {
                    input.Write(byteArray, 0, byteArray.Length);
                }

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();

                // Get the stream associated with the response.
                Stream receiveStream = response.GetResponseStream();

                // Pipes the stream to a higher level stream reader with the required encoding format.
                using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8)) {
                    returnXML = readStream.ReadToEnd();
                }

                receiveStream.Close();
                response.Close();
            }
            catch (WebException we) {

                HttpWebResponse response = ((System.Net.HttpWebResponse)(we.Response));

                throw we;
            }

            return returnXML;
        }
        /// <summary>
        /// Calls the Cybersource API to retrieve a single transaction from their system
        /// </summary>
        /// <param name="qo">The filters in which to search for the transaction</param>
        /// <returns></returns>
        public static CybersourceAPI.Model.Report GetSingleTransaction(CybersourceAPI.QueryObject.SingleTransactionQO qo)
        {
            // Single transaction URL
            string url = qo.IsTestEnvironment ? @"https://ebctest.cybersource.com/ebctest/Query" : string.Format("https://ebc.cybersource.com/ebc/Query");

            // There are a few things that are reequired in order to call Cybersource API
            /// First is the merchant is always required.
            if (string.IsNullOrEmpty(qo.MerchantID)) {
                throw new Exception("Merchant ID is required to call the cybersource API.");
            }

            // Either the merchant reference number and targetDate is required OR the requestID, both cannot be supplied
            if (!string.IsNullOrEmpty(qo.MerchantReferenceNumber)) {
                if (!qo.TargetDate.HasValue) {
                    throw new Exception("Since MerchantReferenceNumber is supplied, a TargetDate is required.");
                }

                if (!string.IsNullOrEmpty(qo.RequestID)) {
                    throw new Exception("Since the MerchantReferenceNumber is supplied, the RequestID must be null.");
                }
            }

            string replyXML = Call(url, qo);
            string docType = "";
            string xmlns = "";

            docType = replyXML.Substring(replyXML.IndexOf("<!DOCTYPE"));
            docType = docType.Substring(0, docType.IndexOf(">") + 1);

            xmlns = replyXML.Substring(replyXML.IndexOf("xmlns"));
            xmlns = xmlns.Substring(0, xmlns.IndexOf("\" ") + 1);

            replyXML = replyXML.Replace(docType, "");
            replyXML = replyXML.Replace(xmlns, "");

            return Serialization.DeserializeFromXmlString<CybersourceAPI.Model.Report>(replyXML);
        }