Updated 409 Conflict responses

Hi,

I’ve noticed an updated response on the Contacts API (perhaps other objects too?) when a 409 conflict happens.

Example:

{
 "message": "Contact already exists. Existing ID: 2926551",
 "identityProfile": {
 "vid": 2926551,
 "identity": [
 {
 "value": "066239b5-a5b8-4caf-af47-ead811935663",
 "type": "LEAD_GUID",
 "timestamp": 1665417061496
 },
 {
 "value": "lee@xyz.co.uk",
 "type": "EMAIL",
 "timestamp": 1665417061370,
 "isPrimary": true
 }
 ],
 "linkedVid": [
 2928301,
 ...
 ],
 "isContact": true,
 "isCanonicalProfile": true,
 "savedAtTimestamp": 1699288594350,
 "promotedToContact": true
 },
 "errors": [
 {
 "message": "A contact with email lee@xyz.co.uk already exists. Existing ID: 2926551",
 "in": "email"
 }
 ],
 "status": "error",
 "correlationId": "b6881283-187e-4088-a778-5c933a14547c",
 "category": "OBJECT_ALREADY_EXISTS",
 "error": "CONTACT_EXISTS"
}

This is a mostly welcome change (not having to parse strings for the conflicting object record is great) however we have several processes running which rely on the category being returned as “category”: “CONFLICT” which is now returned as “category”: “OBJECT_ALREADY_EXISTS” instead. This is resulting in a number of failures which could have been prevented with a bit of notice.

Can anyone clarify whether this is a permanent change or not, and if so has it been documented or announced anywhere?

``

I’ve also observed that change. All good - and I was going to use the retured “existing ID” information until I realized that it wasn’t really part of a JSON structured response, just an ID embedded in a string. Given this I’m not sure we can rely on this format as a documented feature.

I’d love to hear a HubSpot product team response on this one!

Steve

On 2024.03.28 at 9:08AM Pacific Time, our APIs started failing due to this unexpected change.

Our systems were relying on this CONFLICT category in order to divert our logic to update a Contact instead in the scenario a Contact already existed with the given email address.

We purposefully lock our HubSpot SDK (GitHub - HubSpot/hubspot-api-python: HubSpot API Python Client Libraries for V3 version of the API · GitHub) to a particular version to aviod updates (planned and unexpected). This change occurred outside the scope of the SDK and seemingly directly from the closed-source API https://api.hubapi.com

These changes to the API Response objects should be communicated with enough time to make necessary changes to end-users.

Ideally changes to a Response object warrant a new version of the API such that Production systems are not impaired.

At least the change did not happen on a Friday.

We also experienced API responses in a couple scenarios that were changed on Friday March 29, 2024 (without ANY notice). We also were relying on the keys that were previously passed in the response in order to detect CONFLICTS or invalid emails.
What is more frustrating, is we had to hotfix this on our end, and the changes were TEMPORARILY reverted today on April 1st. I literally have 3 logs in a row that show it went from the “new” API to the “old” API back to the “new” API. This is really unacceptable considering there has been 0 communication about these breaking changes.

I am also going to dump out the responses that changed that we were using. As you can see, the keys and data structures are different.

Email Response

This response is how it looked prior to the unannounced March 28th change (which was incidently resurrected today on April 1st)

"response": {
 "statusCode": 400,
 "body": {
 "status": "error",
 "message": "Property values were not valid: [{\"isValid\":false,\"message\":\"Email address ****** is invalid\",\"error\":\"INVALID_EMAIL\",\"name\":\"email\"}]",
 "category": "VALIDATION_ERROR"
 }
}

What the response changed to between March 28 - April 1

"response": {
 "statusCode": 400,
 "body": {
 "validationResults": [
 {
 "isValid": false,
 "message": "Email address ****** is invalid",
 "error": "INVALID_EMAIL",
 "name": "email"
 }
 ],
 "status": "error",
 "message": "Property values were not valid",
 }
}

Unique Validation Response

This response is how it looked prior to the unannounced March 28th change (which was incidently resurrected today on April 1st)

"response": {
 "statusCode": 400,
 "body": {
 "message": "Cannot set PropertyValueCoordinates{portalId=00000000, objectTypeId=ObjectTypeId{legacyObjectType=COMPANY}, propertyName=XXXXXXXXXXX, value=${XXXXXXXXXXX}} on 0000000000. ${hubSpotId} already has that value.",
 "category": "VALIDATION_ERROR"
 }
}

What the response changed to between March 28 - April 1

"response": {
 "statusCode": 400,
 "body": {
 "message": "Cannot set PropertyValueCoordinates{portalId=00000000, objectTypeId=ObjectTypeId{legacyObjectType=COMPANY}, propertyName=XXXXXXXXXXX, value=${XXXXXXXXXXX}} on 0000000000. ${hubSpotId} already has that value.", 
 "errorType": "UNIQUE_VALUE_CONFLICT"
 }
}