stripe-dotnet: Error parsing JSON returned from webhook
Hi, I’ve recently moved to version 21.4.1 from 19.x, and now I’m receiving errors when parsing some webhook events.
Below is some JSON that caused an error in the parser. It looks like it falls over trying to generate a request object - from what it looks like to be an Id only,
I’ve tried both the ParseEvent and ConstructEvent methods - both fail identically.
{ "id": "evt_1DZUr64WLhpec2eZ8YxDi4sm", "object": "event", "api_version": "2014-06-17", "created": 1542941840, "data": { "object": { "id": "card_1DZUqq4WLhpec2eZr2GUSqJW", "object": "card", "address_city": null, "address_country": null, "address_line1": null, "address_line1_check": null, "address_line2": null, "address_state": null, "address_zip": null, "address_zip_check": null, "brand": "Visa", "country": "US", "customer": "cus_4iIYzLmgQznYlK", "cvc_check": "pass", "dynamic_last4": null, "exp_month": 9, "exp_year": 2019, "fingerprint": "tXS6DZYDEDNFUeFL", "funding": "credit", "last4": "4242", "metadata": { }, "name": "Gabe Newell", "tokenization_method": null } }, "livemode": false, "pending_webhooks": 1, "request": "req_7hFEZuZn4RwSm6", "type": "customer.card.deleted" }
Newtonsoft.Json.JsonSerializationException Message = Error converting value “req_7hFEZuZn4RwSm6” to type ‘Stripe.EventRequest’. Path ‘request’, line 36, position 33.
Hack “fix” until this has been sorted out:
var jObject = Newtonsoft.Json.JsonConvert.DeserializeObject<Newtonsoft.Json.Linq.JObject>(json);`
if (jObject["request"] != null)`
{
jObject["request"] = null;
json = jObject.ToString();
}
Cheers, Steve
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 19 (8 by maintainers)
Hi @steve-tapley. The Stripe.net library is pinned to a specific API version, and expects the objects it decodes to be formatted according to that version.
In this case, Stripe.net v21.4.1 is pinned to API version 2018-11-08 (cf. https://github.com/stripe/stripe-dotnet/blob/v21.4.1/src/Stripe.net/Infrastructure/Public/StripeConfiguration.cs#L10). According to the
api_versionkey in the JSON object you shared, the event object you’re trying to decode was formatted with API version 2014-06-17. As such, it’s not unexpected that trying to decode that object would fail. The exact cause is the change in therequestproperty introduced in API version 2017-05-25.When sending requests to Stripe’s API, the Stripe.net library uses the versioning header to force a specific API version. However, event objects are always formatted according to your Stripe account’s default API version. So when using webhooks with the Stripe.net library, it’s important that your account’s default API version matches the API version expected by the Stripe.net library.
You can upgrade to the latest API version (which is currently 2018-11-08, the version expected by Stripe.net v21.4.1) from your dashboard at https://dashboard.stripe.com/developers.
In short, this is expected behavior. I think we can improve the developer experience with a clearer error message though, so I’ll leave this issue open for now.
Not sure if this is working with the new version of stripe or that I am missing something. I have a . net 4.6 environment upgraded to the latest version of Stripe.net for .net and also updated my version to 2019-03-14 on the dashboard, I have: Stream req = Request.InputStream; req.Seek(0, System.IO.SeekOrigin.Begin); string json = new StreamReader(req).ReadToEnd(); (So far its working and if I would write the Json string to for example a database its as the event that was send from the dasboard) The next step always returns an error and stops there, with or without the , true/false: Event stripeEvent = EventUtility.ParseEvent(json);
Any idea?
Hi @dpellizza, thanks for the detailed information. I don’t have much experience with ASP.NET, but I believe this issue is similar to #1361. Basically, ASP.NET won’t automatically fill
Data.Objectbecause doing so requires using theStripeObjectConvertercustom JSON converter, which ASP.NET doesn’t know about.This issue should be fixed in the upcoming v22 version (cf. #1396). In the meantime, you can work around the issue by deserializing the event manually using the
Stripe.EventUtility.ParseEventmethod. Something like this should work:(Not directly related to your issue, but ideally you should use the
Stripe.EventUtility.ConstructEventmethod so that you verify the webhook signature while constructing the event.)Let me know if that helps!
Hi @steve-tapley.
The only API version a particular Stripe.net version is 100% compatible with is the one it’s pinned to. Trying to use a different API version may work for some resources, but not for others. Depending on the exact changes, it may fail silently (e.g. deserialization would appear to work, but some fields would not be filled because the API didn’t return them and other fields would be missing because the API did return them but they’re not present in the library).
You can create a test webhook endpoint with the latest API version, without having to upgrade the API version for the entire account. Once the endpoint is created, you can create test events “organically” (i.e. by sending requests that would result in the events you want, not by using the “Send test webhook” button) and those events will be formatted with the latest API version.
Right, I think the advice in those docs is mostly applicable to our client libraries that are not pinned to a specific API version, like Ruby or PHP. Things are a lot easier there, because those libraries don’t care about specific resource formats.
For Stripe.net, my recommendation would be to do something like this:
That last step is difficult to do in one go, so you may want to temporarily force your webhook handler to return a non-2xx status code temporarily so that Stripe will retry those events ~one hour later.
I realize all this is not ideal and we can definitely do better to improve the experience. I’ll share your feedback internally.
@phil118 As of v20.0.0, the
Data.Objectproperty ofEventobjects is directly instantiated to the correct type. You can either use pattern matching or use theEventobject’sTypeproperty to cast to the correct type. You can find more information here: https://github.com/stripe/stripe-dotnet/wiki/Migration-guide-for-v20#interfaces-for-polymorphic-resources.