/// <summary>
        ///
        /// </summary>
        /// <typeparam name="TRequest"></typeparam>
        /// <param name="request"></param>
        /// <param name="metadata"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public virtual async Task CallAsync <TRequest>(TRequest request, IDictionary <string, object> metadata, CancellationToken cancellationToken)
        {
            try
            {
                if (!(request is MessageData messageData))
                {
                    throw new Exception("injected wrong implementation");
                }

                //todo refactor into a single call and a dto
                var uri             = RequestBuilder.BuildUri(WebhookConfig, messageData.Payload);
                var httpMethod      = RequestBuilder.SelectHttpMethod(WebhookConfig, messageData.Payload);
                var originalPayload = RequestBuilder.BuildPayload(WebhookConfig, messageData.Payload, metadata);
                var payload         = WebhookConfig.PayloadTransformation == PayloadContractTypeEnum.WrapperContract
                    ? WrapPayload(originalPayload, WebhookConfig, messageData)
                    : originalPayload;

                var config  = RequestBuilder.SelectWebhookConfig(WebhookConfig, messageData.Payload);
                var headers = RequestBuilder.GetHttpHeaders(WebhookConfig, messageData);
                var authenticationConfig = RequestBuilder.GetAuthenticationConfig(WebhookConfig, messageData.Payload);

                var httpClient = HttpClientFactory.Get(config);

                await AddAuthenticationHeaderAsync(cancellationToken, authenticationConfig, headers);

                var response = await httpClient.SendRequestReliablyAsync(httpMethod, uri, headers, payload, cancellationToken);

                await _requestLogger.LogAsync(httpClient, response, messageData, uri, httpMethod, headers);
            }
            catch (Exception e)
            {
                BigBrother.Publish(e.ToExceptionEvent());
                throw;
            }
        }