Parsing JSON response from HubSpot API with C#

I’m stuck trying to parse JSON data that comes back from HubSpot’s Contact API. I’m working with RestSharp and Newtonsoft.Json but can’t figure out how to set up my C# classes properly to handle the JSON structure.

Here’s a sample of what the API returns:

{
  "leads": [
    {
      "id": 1001,
      "account-id": 7788991,
      "active": true,
      "profile-link": "https://app.hubspot.com/contacts/7788991/contact/1001",
      "fields": {
        "name": {
          "value": "John"
        },
        "modified": {
          "value": "1654321987654"
        },
        "organization": {
          "value": "Tech Solutions Ltd"
        },
        "surname": {
          "value": "Smith"
        }
      },
      "submissions": [],
      "profiles": [
        {
          "id": 1001,
          "created-timestamp": 1553635648634,
          "removed-timestamp": 0,
          "data": [
            {
              "type": "EMAIL",
              "value": "[email protected]",
              "timestamp": 1553635648591,
              "primary": true
            },
            {
              "type": "GUID",
              "value": "x9876",
              "timestamp": 1553635648630
            }
          ]
        }
      ]
    }
  ],
  "more-results": false,
  "next-id": 1501
}

I can get the basic ID values without problems, but when I try to access the nested properties section everything breaks. Any ideas on the right class structure?

I’ve been working with HubSpot integrations for years - building custom parsers for their API is pointless. They change stuff every few months and break your C# classes.

Forget RestSharp, JsonProperty attributes, and nested dictionaries. I handle all HubSpot data through automation workflows now. Zero parsing code.

Just set up a workflow that hits HubSpot’s Contact API, transforms the messy JSON into clean data, then pushes it to your database or wherever. The platform deals with all the weird field names and nested objects.

When HubSpot changes their response format (and they will), you update the workflow mapping instead of rewriting classes. You can add validation, filtering, and transformations without code changes.

Migrated three HubSpot integrations this way and haven’t touched a JsonProperty attribute since. Way more maintainable.

This happens because HubSpot’s property naming is inconsistent and the structure is nested weirdly. I hit the same issue integrating their Contacts API into our CRM about six months ago.

Here’s what worked for me:

Start with a root HubSpotResponse class that has a leads array. For each lead, use JsonPropertyName attributes to handle the hyphenated properties - “account-id” becomes AccountId in your C# class.

The fields object is the tricky part since property names change dynamically. I created a ContactFields class that inherits from Dictionary<string, HubSpotFieldValue>. HubSpotFieldValue just has a Value property as a string. This lets you access any field without breaking when HubSpot adds new ones.

For profiles, make a separate ProfileData class with a data array. The objects inside have type, value, and timestamp properties. The type tells you if it’s EMAIL, GUID, or whatever.

One thing that’ll bite you - HubSpot randomly returns nulls in weird places. Make all your properties nullable or you’ll get deserialization exceptions.

HubSpot API parsing sucks - I’ve fought with those nested structures and weird property names too.

Here’s what I learned: don’t write parsing code. Automate the whole thing instead. I ditched RestSharp and JSON classes for API work like this.

Skip the custom C# classes and dictionary mess for dynamic fields. Use automation to handle HubSpot data flow. Set up triggers that process new contacts automatically, transform data how you want, and send it wherever.

No JsonProperty attributes. No nested classes. No parsing headaches. The automation platform deals with API complexity so you can focus on actually using the contact data.

I’ve got workflows pulling HubSpot contacts, cleaning data, and pushing to our internal systems - zero custom parsing code. Way more reliable than maintaining C# models that break every time HubSpot tweaks their response format.

Check it out: https://latenode.com

those hyphenated properties are annoying, but here’s what works better - use JObject.Parse() then pull out what you need by hand. skip the complex class setup for hubspot’s messy json. parse it as dynamic, grab the values you want, then map to your own clean c# models. way easier than wrestling with JsonProperty attributes and nested dictionaries.

Yeah, HubSpot’s nested fields threw me for a loop when I integrated it last month. Tried a bunch of different ways before finding what actually works. Here’s what I’d do: use strongly-typed classes for the main stuff (leads array, id, account-id), but switch to JToken just for the fields section. Deserialize the response normally, then grab individual values with response.Leads[0].Fields.SelectToken(“name.value”). Way cleaner than wrestling with complex dictionaries, and it handles HubSpot’s random field changes without breaking your code. Keep the profiles array strongly-typed since that structure never changes. Watch out for timestamps though - they’re sometimes strings, sometimes numbers depending on field type. Parse as strings first, then convert.

Your main problem is those nested properties with dynamic field names - they don’t play nice with strongly-typed C# properties. I hit the same wall with HubSpot’s API last year. Use Dictionary<string, FieldValue> for the fields object instead of creating individual properties for each field. Make a simple FieldValue class with just a ‘value’ property and your fields collection becomes way easier to handle. For the profiles array, you’ll need separate classes for different types like EmailData and GuidData, or go with a base class that can discriminate types. Those hyphens in property names like ‘account-id’ will break things - fix them with JsonProperty attributes. I ended up creating separate response models just for the API, then mapping to my business objects afterward. Way cleaner than trying to make one class do everything.