События PayPal Webhook не запускаются в режиме песочницы
Я использую PayPal Rest API, более конкретно PayPal .Net SDK для моего проекта, и мне это очень нравится.
Моя проблема в том, что до сих пор я не могу получать никаких уведомлений от PayPal.
Примечание: однако симулятор webhook работает, мой обработчик правильно получает сообщение json от PayPal.
Вот шаги, которые я делаю:
После успешного создания нового счета-фактуры (с использованием учетных данных "песочницы" из моего приложения PayPal) я отправляю его на тестовый счет покупателя.
Я открываю ссылку в уведомлении, чтобы просмотреть счет, и оплачиваю его с помощью тестового счета покупателя.
И фасилитатор, и покупатель получают уведомление о том, что счет был успешно оплачен.
На моем сервере ничего не происходит. На конечной точке моего слушателя не было получено ни одного запроса о событии webhook.
У меня есть активный слушатель событий webhook в конфигурации песочницы моего приложения, отслеживающий все возможные события.
В чем может быть причина того, что PayPal не запускает никаких событий?
Я пока не хочу переходить на IPN, и периодическая итерация по списку счетов из результатов поиска также не является эффективной альтернативой.
Обновить:
Поскольку сервер событий sandho webhook снова запущен и работает, я заставил его работать, используя следующий код (действие контроллера C#). Обратите внимание, что структура тела json, запущенная из симулятора webhook, отличается от структуры, отправленной после оплаты счета. Поэтому я расширил объект WebHookEvt из PayPal SDK соответственно.
/// <summary>
/// PayPal Webhook handler
/// </summary>
/// <param name="evt"></param>
/// <returns></returns>
[HttpPost]
public ActionResult EventHandler(WebhookEvent evt) { // [System.Web.Http.FromBody]
string json = null;
Capture capture = null;
InvoiceObject invoiceObject = null;
InvoiceExt invoice = null;
WebHookEventCapture captureEvent = null;
WebHookEventInvoice invoiceEvent = null;
if (evt == null) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
} else {
this.logger.Debug(string.Format("***** Webhook event type [{0}] received from PayPal *****", evt.event_type));
logger.Debug(string.Format("Event id: {0}", evt.id));
logger.Debug(string.Format("Event create time: {0}", evt.create_time));
logger.Debug(string.Format("Event type: {0}", evt.event_type));
logger.Debug(string.Format("Event resource: {0}", evt.resource));
logger.Debug(string.Format("Event resource type: {0}", evt.resource_type));
logger.Debug(string.Format("Event summary: {0}", evt.summary));
using (Stream req = Request.InputStream) {
req.Seek(0, System.IO.SeekOrigin.Begin);
using (StreamReader sr = new StreamReader(req)) {
json = sr.ReadToEnd();
}
}
logger.Debug(string.Format("WebHook request json form PayPal: ***{0}***", json));
// Validate webhook event
bool isValid = WebhookEvent.ValidateReceivedEvent(new PayPalPaymentProvider(IPN_SANDBOX_MODE).Context, Request.Headers, json, WEBHOOK_ID_INVOICE_PAID);
logger.Debug(string.Format("Validating webhook event... Is valid = {0}", isValid ? "TRUE" : "FALSE"));
try {
if ("capture".Equals(evt.resource_type)) {
captureEvent = JsonConvert.DeserializeObject<WebHookEventCapture>(json);
capture = captureEvent.resource;
} else if ("invoices".Equals(evt.resource_type)) {
invoiceEvent = JsonConvert.DeserializeObject<WebHookEventInvoice>(json);
invoiceObject = invoiceEvent.resource;
invoice = invoiceObject.invoice;
}
//if (capture != null) {
// logger.Debug(string.Format("Capture amount: {0}", capture.amount));
// logger.Debug(string.Format("Capture create time: {0}", capture.create_time));
// logger.Debug(string.Format("Capture id: {0}", capture.id));
// logger.Debug(string.Format("Capture is final: {0}", capture.is_final_capture.HasValue ? capture.is_final_capture : false));
// logger.Debug(string.Format("Capture parent payment: {0}", capture.parent_payment));
// logger.Debug(string.Format("Capture state: {0}", capture.state));
// logger.Debug(string.Format("Capture transaction fee: {0}", capture.transaction_fee));
// logger.Debug(string.Format("Capture update time: {0}", capture.update_time));
//}
if (isValid && invoice != null) {
logger.Debug(string.Format("Invoice [{0}]", invoice));
logger.Debug(string.Format("Invoice id: [{0}]", invoice.id));
logger.Debug(string.Format("Invoice merchant memo: [{0}]", invoice.merchant_memo));
logger.Debug(string.Format("Invoice date: [{0}]", invoice.invoice_date));
logger.Debug(string.Format("Invoice status: [{0}]", invoice.status));
logger.Debug(string.Format("Invoice total amount: [{0}]", invoice.total_amount != null ? invoice.total_amount.currency + invoice.total_amount.value : "??"));
if (invoice.billingInfo != null) { // billing_info
foreach (var billingInfo in invoice.billingInfo) {
logger.Debug(string.Format("Invoice billing info address: {0}", billingInfo.address ?? new InvoiceAddress()));
logger.Debug(string.Format("Invoice billing info business name: {0}", billingInfo.business_name ?? "??"));
logger.Debug(string.Format("Invoice billing info email: {0}", billingInfo.email ?? "??"));
logger.Debug(string.Format("Invoice billing info first name: {0}", billingInfo.first_name ?? "??"));
logger.Debug(string.Format("Invoice billing info last name: {0}", billingInfo.last_name ?? "??"));
logger.Debug(string.Format("Invoice billing info language: {0}", billingInfo.language ?? "??"));
logger.Debug(string.Format("Invoice billing info notification channel: {0}", billingInfo.notification_channel ?? "??"));
logger.Debug(string.Format("Invoice billing info phone: {0}", billingInfo.phone ?? new Phone()));
}
}
// Update clientproductpayment
SubscriptionRepository db = new SubscriptionRepository();
var subscription = db.Context.ClientProductPayments.Where(
q => invoice.id.Equals(q.TransactionId)).FirstOrDefault();
if (subscription != null) {
logger.Debug(string.Format("Subscription (ClientProductPayment) with transaction_id = [{0}] found", invoice.id));
// Update subscription
db.RegisterPayment(subscription, invoice.id);
logger.Debug(string.Format(
"Subscription (ClientProductPayment) with id = [{0}] updated successfully with transaction id = [{1}]",
subscription.Id, invoice.id));
} else {
logger.Warn(string.Format("Subscription (ClientProductPayment) with transaction_id = [{0}] not found", invoice.id));
}
}
}
catch (Exception e) {
logger.Error(e.Message, e);
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
}
logger.Debug("Sending Http status code 200 response...");
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
Расширение WebHookEvt
using Newtonsoft.Json;
using PayPal.Api;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PaymentManager.Provider {
public class WebHookEventCapture : WebhookEvent {
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "resource")]
public new Capture resource { get; set; }
}
public class WebHookEventInvoice : WebhookEvent {
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "resource")]
public new InvoiceObject resource { get; set; }
}
public class InvoiceObject {
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "invoice")]
public InvoiceExt invoice { get; set; }
}
public class InvoiceExt : Invoice {
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "billingInfo")]
public List<BillingInfo> billingInfo { get; set; }
}
}
1 ответ
Мы сожалеем об этом. На нашей стороне была временная проблема, которая была исправлена. Вы должны быть в состоянии получать уведомления о Webhook Invoicing сейчас. Пожалуйста, попробуйте их и дайте нам знать, как это происходит.
Спасибо