I am unable to get paypal to verify the webhook request through the webhooks simulator. The only difference between my VerifyTask and the example is that I converted from webclient to HttpClient. This code is as close to the example ipn listener from the paypal site. The following is c# asp.net code:
public class IPNSendBack
{
public HttpRequest? IPNRequest { get; set; }
public string? RequestBody { get; set; }
public string? Verification { get; set; }
}
[AllowAnonymous]
[HttpPost()]
public async Task<IActionResult> ReceiveWebHook()
{
var headers = HttpContext.Request.Headers;
string transmissionid = headers["Paypal-Transmission-Id"].ToString();
IPNSendBack ipnContext = new IPNSendBack()
{
IPNRequest = Request
};
using (StreamReader reader = new StreamReader(ipnContext.IPNRequest.Body, Encoding.ASCII))
{
ipnContext.RequestBody = await reader.ReadToEndAsync();
}
await Task.Run(() => VerifyTask(ipnContext, transmissionid));
}
private async Task VerifyTask(IPNSendBack ipnContext, string? transmissionid)
{
string url = isSandbox
? "https://ipnpb.sandbox.paypal.com/cgi-bin/webscr"
: "https://ipnpb.paypal.com/cgi-bin/webscr";
using (HttpClient client = new HttpClient())
{
// Set values for the verification request
var content = new StringContent($"cmd=_notify-validate&{ipnContext.RequestBody}", Encoding.ASCII, "application/x-www-form-urlencoded");
// Send the request to PayPal and get the response
HttpResponseMessage response = await client.PostAsync(url, content);
response.EnsureSuccessStatusCode(); // Ensure successful response
if (response.IsSuccessStatusCode)
{
string verificationResult = await response.Content.ReadAsStringAsync();
ipnContext.Verification = verificationResult;
}
}
await ProcessVerificationResponse(ipnContext, transmissionid);
}
Aside from the always getting the INVALID response, I am able to get what I need and can properly process the response body, so I know the request body is good, at least from the simulator.
Based on the response, I have modified my code as follows:
public async Task<IActionResult> RecieveWebHook()
{
APICredentials credentials = new APICredentials(Mode);
string payload;
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
payload = await reader.ReadToEndAsync();
}
//var content = new StringContent(payload, Encoding.UTF8, "application/json");
VerifyObj vo = new VerifyObj()
{
transmission_id = requestheaders["Paypal-Transmission-Id"].ToString(),
transmission_time = requestheaders["Paypal-Transmission-Time"].ToString(),
cert_url = requestheaders["Paypal-Cert-Url"].ToString(),
auth_algo = requestheaders["Paypal-Auth-Algo"].ToString(),
transmission_sig = requestheaders["Paypal-Transmission-Sig"].ToString(),
webhook_id = credentials.WebHookId,
webhook_event = payload
};
string data = JsonSerializer.Serialize(vo);
HttpRequestMessage requestMsg = new HttpRequestMessage(HttpMethod.Post, credentials.Url);
requestMsg.Headers.Add("accept","application/json");
//requestMsg.Headers.Add("Authorization", $"Bearer {credentials.Secret}");
requestMsg.Content = new StringContent(data, Encoding.UTF8, "application/json");
try
{
using (HttpClient client = new HttpClient())
{
var response = await client.SendAsync(requestMsg);
if (response.IsSuccessStatusCode)
{
string verificationResult = await response.Content.ReadAsStringAsync();
}
}
}
catch (Exception ex)
{
}
return Ok();
}
it is still not validating. I commented out the Authorization Header, clearly my webhook secret is not what it is looking for. What is it and where do I get it?
PayPal Webhooks and IPN (Instant Payment Notification) are two different services. There is no connection between the two. A simple way to distinguish them is that Webhooks are always in JSON format, and IPN messages are always in NVP or name-value pair format (&name=value
).
Assuming you are interested in validating a PayPal Webhook message in JSON format, there are two methods.
The code in your question appears to be for IPN, which again is irrelevant to PayPal Webhooks.