hubspothubspot-crm

Hubspot Bulk Import CRM Data API question


I've been using the hubspot documentation to attempt a batch upload contacts that have a first name, age, phone number, city, and site url with hubspots CRM API. I've tried with both a csv file, and an xlsx file with five rows of test data (I'd changed fileFormat to CSV and SPREADSHEET when testing them both). I have the file sitting in the same directory as my python program that calls it, so I know pathing is not an issue.

Here's my python code:

import requests
import json

post_url = 'http://api.hubapi.com/crm/v3/imports?hapikey=c76....901'

latest_file = "thisIsTestData.csv"

headers = {'accept': 'application/json'}

data = {
    "name": "import_contacts",
    "files": [
        {
            "fileName": latest_file,
            "fileFormat": "CSV",
            "fileImportPage": {
                "hasHeader": True,
                "columnMappings": [
                    {
                        "ignored": False,
                        "columnName": "FirstName",
                        "idColumnType": None,
                        "propertName": "firstname",
                        "foreignKeyType": None,
                        "columnObjectType": "CONTACT",
                        "associationIdentifiedColumn": False
                    },
                    {
                        "ignored": False,
                        "columnName": "Web Site URL",
                        "idColumnType": None,
                        "propertyName": "website",
                        "foreignKeyType": None,
                        "columnObjectType": "CONTACT",
                        "associationIdentifiedColumn": False
                    },
                    {
                        "ignored": False,
                        "columnName": "Ad_Age",
                        "idColumnType": None,
                        "propertyName": "ad_age",
                        "foreignKeyType": None,
                        "columnObjectType": "CONTACT",
                        "associationIdentifiedColumn": False
                    },
                    {
                        "ignored": False,
                        "columnName": "City",
                        "idColumnType": None,
                        "propertyName": "city",
                        "foreignKeyType": None,
                        "columnObjectType": "CONTACT",
                        "associationIdentifiedColumn": False
                    },
                    {
                        "ignored": False,
                        "columnName": "Mobile Phone Number",
                        "idColumnType": None,
                        "propertyName": "mobilephone",
                        "foreignKeyType": None,
                        "columnObjectType": "CONTACT",
                        "associationIdentifiedColumn": False
                    },
                ]
            }
        }
    ]
}


r = requests.post(url=post_url, data=data, headers=headers)

print(r.status_code)
print(r.text)

I've added a status_code print at the bottom, and receive a 415 response. I checked hubspot, and none of the test values have been uploaded so I know something is definitely not working. The file is in the correct location, I've used the account settings to verify that the column mappings are correctly named and match the existing column names in the csv and xlsx, the api key is correct, and I've got the request set to POST. Unfortunately the hubspot docs do not have an example of a working post example, so I can't use anything existing to troubleshoot my issues. I'm not sure at this point what it is I'm missing, and any help or guidance would be appreciated.


Solution

  • It took all week of grinding away and talking with their internal support about what was missing from their documentation, but I finally got it working.

    The header should not have been {'accept': 'application/json'} like in most of their other documentation. Instead it required {"importRequest": datastring} followed by a jsonified string of the data object. A files object also had to be created, and allowed to read the absolute path to the file in binary. In the final post request line, it used the crafted url with api key, the jsonified data string, and finally the binary reading of the csv file.

    Any column value in the csv that you did not want transferred over, had to be marked with "ignored":True, instead of omitted from the data configuration. The data had to be listed in the same order they appear in the csv file as well.

    Here's my updated code that reflects a lot of the changes that were needed.

    import os
    import requests
    import json
    
    url = "http://api.hubapi.com/crm/v3/imports?hapikey={insert HAPI KEY HERE}"
    full_path = os.path.abspath("TestData.csv")
    data = {
        "name": "test_import",
        "files": [
            {
                "fileName": "TestData.csv",
                "fileFormat": "CSV",
                "fileImportPage": {
                    "hasHeader": True,
                    "columnMappings": [
                        {
                            "ignored": False,
                            "columnName": "Web Site URL",
                            "idColumnType": None,
                            "propertyName": "website",
                            "foreignKeyType": None,
                            "columnObjectType": "CONTACT",
                            "associationIdentifiedColumn": False
                        },
                        {
                            "ignored": False,
                            "columnName": "FirstName",
                            "idColumnType": None,
                            "propertyName": "firstname",
                            "foreignKeyType": None,
                            "columnObjectType": "CONTACT",
                            "associationIdentifierColumn": False
                        },
                        {
                            "ignored": False,
                            "columnName": "Ad_Age",
                            "idColumnType": None,
                            "propertyName": "ad_age",
                            "foreignKeyType": None,
                            "columnObjectType": "CONTACT",
                            "associationIdentifiedColumn": False
                        },
    
                        {
                            "ignored": False,
                            "columnName": "Mobile Phone Number",
                            "idColumnType": None,
                            "propertyName": "mobilephone",
                            "foreignKeyType": None,
                            "columnObjectType": "CONTACT",
                            "associationIdentifiedColumn": False
                        },
                        {
                            "ignored": False,
                            "columnName": "City",
                            "idColumnType": None,
                            "propertyName": "city",
                            "foreignKeyType": None,
                            "columnObjectType": "CONTACT",
                            "associationIdentifiedColumn": False
                        },
                        {
                            "ignored": True,
                            "columnName": "Create Date"
                        },
                        {
                            "ignored": True,
                            "columnName": "Stock Photo"
                        }
                    ]
                }
            }
        ]}
    
    datastring = json.dumps(data)
    
    payload = {"importRequest": datastring}
    
    files = [
        ('files', open(full_path, 'rb'))
    ]
    
    
    response = requests.request("POST", url, data=payload, files=files)
    #Output checking
    print(response.text.encode('utf8'))
    print(response.status_code)