You can create, read, and update custom objects using API key authentication. If you’d like to integrate a custom object with your HubSpot app using OAuth, learn more about applying to the OAuth pilot program.

Custom objects

APPLICABLE PRODUCTS
  • Marketing Hub
    • Enterprise
  • Sales Hub
    • Enterprise
  • Service Hub
    • Enterprise
  • CMS Hub
    • Enterprise

HubSpot provides a set of standard CRM objects with each account, such as contacts, companies, and deals. However, you can also create your own custom objects to represent and organize your CRM data based on your business needs. Use the custom objects API to define custom objects, properties, and associations to other CRM objects.

For a video walkthrough of custom objects, check out Data in HubSpot: Custom Objects and Other Tools in HubSpot’s Academy.

Below, learn how to create and manage custom objects through the API, and see a walkthrough of creating an example custom object.

Create a custom object

Please note: custom objects are specific to each account, with a maximum of 10 custom objects per account.

To create a custom object, you'll first need to define the object schema. The schema includes the object name, properties, and associations to other CRM objects. You can find the full schema request details in the Object Definition tab at the top of this article. You can also view a sample request in the example walkthrough below.

To create the custom object schema, make a POST request to crm/v3/schemas. In the request body, include definitions for your object schema, including its name, properties, and associations.

When naming your custom object, keep the following in mind:

  • Once you create an object, the object's name and label cannot be changed.
  • Long labels may be cut off in certain parts of the product.
  • Avoid using all caps. If possible, only capitalize the first letter of the first word.

Below, read about the required definitions for the object's properties and associations. 

Properties

The properties you define in the request body will be used to store information on individual custom object records. You'll also use those properties to populate the following property-based fields:

  • requiredProperties: the properties that are required when creating a new custom object record.
  • searchableProperties: the properties that are indexed for searching in HubSpot.
  • primaryDisplayProperty: the property used for naming individual custom object records.
  • secondaryDisplayProperties: the properties that appear on individual records under the primaryDisplayProperty. custom-object-secondary-display-properties0
    • The first property listed in secondaryDisplayProperties will be also added as a fourth filter on the object index page if it’s one of the following property types:
      • string
      • number
      • enumeration
      • boolean
      • datetime
        custom-object-dashboard-filter0
    • To remove a display property from the UI, you'll need to first delete the property, then recreate it.

By default, when creating properties through the schema request, property type is set to string, and the fieldType is set to text. Below are the values you can use to create different types of properties.

Valid values for type
type Description Valid fieldType values
enumeration A string representing a set of options, separated by semicolons.  booleancheckbox, checkbox, radio, select
date An ISO 8601 formatted value representing a specific day, month, and year. date
dateTime An ISO 8601 formatted value representing a specific day, month, year and time of day. The HubSpot app will not display the time of day. date
string A plain text strings, limited to 65,536 characters. file, text, textarea
number A number value containing numeric digits and at most one decimal. number
Valid values for fieldType 
fieldType Description
booleancheckbox An input that will allow users to select one of either Yes or No. When used in a form, it will be displayed as a single checkbox.
checkbox A list of checkboxes that will allow a user to select multiple options from a set of options allowed for the property.
date A date value, displayed as a date picker.
file Allows for a file to be uploaded to a form. Stored and displayed as a URL link to the file.
number A string of numerals or numbers written in decimal or scientific notation.
radio An input that will allow users to select one of a set of options allowed for the property. When used in a form, this will be displayed as a set of radio buttons.
select A dropdown input that will allow users to select one of a set of options allowed for the property.
text A plain text string, displayed in a single line text input.
textarea A plain text string, displayed as a multi-line text input.

Associations

HubSpot will automatically associate a custom object with the emails, meetings, notes, tasks, calls, and conversations objects. You can further associate your custom object with other standard HubSpot objects or other custom objects.

When creating associations through the create schema request, identify standard objects using their name and custom objects using their objectTypeId value. For example: 

JSON
// Example associatedObjects array

"associatedObjects": [
"CONTACT",
"COMPANY",
"TICKET",
"DEAL",
"2-3453932"
]

Retrieve existing custom objects

To retrieve all custom objects, make a GET request to /crm/v3/schemas.

To retrieve a specific custom object, make a GET request to one of the following endpoints:

  • /crm/v3/schemas/{objectTypeId}
  • /crm/v3/schemas/{fullyQualifiedName}. You can find an object's

    fullyQualifiedName in its schema, which is derived from p{portal_id}_{object_name}.

For example, your request URL may look like the following:

https://api.hubapi.com/crm/v3/schemas/2-3465404

Update existing custom objects

To update an object's schema, make a PATCH request to https://api.hubapi.com/crm/v3/schemas/{objectTypeId}.

Once your custom object is defined, the name and labels (singular and plural) cannot be changed. However, you can update the requiredProperties, searchableProperties, primaryDisplayProperty, and secondaryDisplayProperties fields.

You can update an object's properties either in HubSpot or by using the properties API.

Update associations

To add other object associations to your custom object, make a POST request to /crm/v3/schemas/{objectTypeId}/associations.

You can only associate your custom object with standard HubSpot objects (e.g. contact, company, deal, or ticket) or other custom objects. In the toObjectTypeId field, identify custom objects by their objectTypeId value and standard objects by their name. For example:

JSON
// Example association request body
{
"fromObjectTypeId": "2-3444025",
"toObjectTypeId": "ticket",
"name": "cat_to_ticket"
}

Delete a custom object

You can only delete a custom object after all object instances of that type are deleted. To delete a custom object, make a DELETE request to /crm/v3/schemas/{objectType}.

If you need to create a new custom object with the same name as the deleted object, you must hard delete the schema by making a DELETE request to /crm/v3/schemas/{objectType}?archived=true. You can only delete a custom object type after all object instances of that type, associations, and custom object properties are deleted.


Custom Object Example

The following is a walkthrough of creating an example custom object. For full details of the requests shown, view the Object Definition tab at the top of the article.

This walkthrough covers:

  1. creating a custom object schema.
  2. creating a custom object record.
  3. associating a custom object record with a HubSpot contact.
  4. creating a new association definition between the custom object and HubSpot ticket.
  5. creating a new property definition.
  6. updating the object schema (i.e. secondaryDisplayProperties) with the new property.

Goal: a car dealership called CarSpot wants to store their inventory in HubSpot using a custom object. To track vehicle ownership and purchases, they'll associate cars with contact records. Along the way, they'll also track vehicle maintenance using HubSpot tickets and custom properties.

Creating the object schema

CarSpot needs to create an object schema that can represent the following attributes as properties: 

  1. Condition (new or used): enumeration
  2. Date received at dealership: date
  3. Year: number
  4. Make: string
  5. Model: string
  6. VIN: string (unique value)
  7. Color: string
  8. Mileage: number
  9. Price: number
  10. Notes: string

They'll also define an association between their custom object and the standard contacts object so that they can connect cars to potential buyers. 

With their data model finalized, they'll create the object schema by making a POST request to /crm/v3/schemas with the following request body:all

JSON
// Example POST request to https://api.hubspot.com/crm/v3/schemas

{
  "name": "car",
  "labels": {
    "singular": "Car",
    "plural": "Cars"
  },
  "primaryDisplayProperty": "model",
  "secondaryDisplayProperties": [
     "make"
],
  "searchableProperties": [
     "year",
     "make",
     "vin",
     "model"
],
  "requiredProperties": [
     "year",
     "make",
     "vin",
     "model"
  ],
  "properties": [
    {
      "name": "condition",
      "label": "Condition",
      "type": "enumeration",
      "fieldType": "select",
      "options": [
        {
          "label": "New",
          "value": "new"
        },
        {
          "label": "Used",
          "value": "used"
        }
      ]
    },
    {
      "name": "date_received",
      "label": "Date received",
      "type": "date",
      "fieldType": "date"
    },
    {
      "name": "year",
      "label": "Year",
      "type": "number",
      "fieldType": "number"
    },
    {
      "name": "make",
      "label": "Make",
      "type": "string",
      "fieldType": "text"
    },
    {
      "name": "model",
      "label": "Model",
      "type": "string",
      "fieldType": "text"
    },
    {
      "name": "vin",
      "label": "VIN",
      "type": "string",
      "hasUniqueValue": true,
      "fieldType": "text"
    },
    {
      "name": "color",
      "label": "Color",
      "type": "string",
      "fieldType": "text"
    },
    {
      "name": "mileage",
      "label": "Mileage",
      "type": "number",
      "fieldType": "number"
    },
    {
      "name": "price",
      "label": "Price",
      "type": "number",
      "fieldType": "number"
    },
    {
      "name": "notes",
      "label": "Notes",
      "type": "string",
      "fieldType": "text"
    }
  ],
  "associatedObjects": [
    "CONTACT"
  ]
}

The response for this API call would look similar to:Copy all

JSON
// Example response body

HTTP 201

{
  "name": "car"
  "labels": {
    "singular": "Car",
    "plural": "Cars"
  }, 
  "primaryDisplayProperty": "model",
   "secondaryDisplayProperties": [
     "make"
  ],
  "searchableProperties": [
    "year",
    "make",
    "vin",
    "model"
  ],
  "requiredProperties": [
    "year",
    "make",
    "vin",
    "model"
  ],
  "archived": false,
  "restorable": true,
  "metaType": "PORTAL_SPECIFIC",
  "id": "3465404",
  "fullyQualifiedName": "p1234567_cars",
  "createdAt": "2021-10-01T15:15:07.340Z",
  "updatedAt": "2021-10-01T15:15:07.340Z",
  "objectTypeId": "2-3465404",
  "properties": [
    {
{
  "id": "529881",
  "createdAt": "2020-02-23T01:24:54.508774Z",
  "updatedAt": "2020-02-23T01:24:54.508774Z",
  "properties": [
    {
      "updatedAt": "2020-02-23T01:24:54.665Z",
      "createdAt": "2020-02-23T01:24:54.665Z",
      "name": "condition",
      "label": "Condition",
      "type": "enumeration",
      "fieldType": "select",
      "groupName": "car_information",
      "options": [
        {
          "label": "New",
          "value": "new",
          "displayOrder": -1,
          "hidden": false
        },
        {
          "label": "Used",
          "value": "used",
          "displayOrder": -1,
          "hidden": false
        }
      ],
      "displayOrder": -1,
      "calculated": false,
      "externalOptions": false,
      "archived": false,
      "hasUniqueValue": false,
      "hidden": false,
      "modificationMetadata": {
        "archivable": true,
        "readOnlyDefinition": false,
        "readOnlyValue": false
      },
      "formField": false
    },
    {
      "updatedAt": "2020-02-23T01:24:54.667Z",
      "createdAt": "2020-02-23T01:24:54.667Z",
      "name": "date_received",
      "label": "Date received",
      "type": "date",
      "fieldType": "date",
      "groupName": "car_information",
      "displayOrder": -1,
      "calculated": false,
      "externalOptions": false,
      "archived": false,
      "hasUniqueValue": false,
      "hidden": false,
      "modificationMetadata": {
        "archivable": true,
        "readOnlyDefinition": false,
        "readOnlyValue": false
      },
      "formField": false
    },
    {
      "updatedAt": "2020-02-23T01:24:54.667Z",
      "createdAt": "2020-02-23T01:24:54.667Z",
      "name": "year",
      "label": "Year",
      "type": "number",
      "fieldType": "number",
      "groupName": "car_information",
      "displayOrder": -1,
      "calculated": false,
      "externalOptions": false,
      "archived": false,
      "hasUniqueValue": false,
      "hidden": false,
      "modificationMetadata": {
        "archivable": true,
        "readOnlyDefinition": false,
        "readOnlyValue": false
      },
      "formField": false
    },
    {
      "updatedAt": "2020-02-23T01:24:54.670Z",
      "createdAt": "2020-02-23T01:24:54.670Z",
      "name": "model",
      "label": "Model",
      "type": "string",
      "fieldType": "text",
      "groupName": "car_information",
      "displayOrder": -1,
      "calculated": false,
      "externalOptions": false,
      "archived": false,
      "hasUniqueValue": false,
      "hidden": false,
      "modificationMetadata": {
        "archivable": true,
        "readOnlyDefinition": false,
        "readOnlyValue": false
      },
      "formField": false
    },
    {
      "updatedAt": "2020-02-23T01:24:54.670Z",
      "createdAt": "2020-02-23T01:24:54.670Z",
      "name": "vin",
      "label": "VIN",
      "type": "string",
      "fieldType": "text",
      "groupName": "car_information",
      "displayOrder": -1,
      "calculated": false,
      "externalOptions": false,
      "archived": false,
      "hasUniqueValue": true,
      "hidden": false,
      "modificationMetadata": {
        "archivable": true,
        "readOnlyDefinition": false,
        "readOnlyValue": false
      },
      "formField": false
    },
    {
      "updatedAt": "2020-02-23T01:24:54.670Z",
      "createdAt": "2020-02-23T01:24:54.670Z",
      "name": "notes",
      "label": "Notes",
      "type": "string",
      "fieldType": "text",
      "groupName": "car_information",
      "displayOrder": -1,
      "calculated": false,
      "externalOptions": false,
      "archived": false,
      "hasUniqueValue": false,
      "hidden": false,
      "modificationMetadata": {
        "archivable": true,
        "readOnlyDefinition": false,
        "readOnlyValue": false
      },
      "formField": false
    },
    {
      "updatedAt": "2020-02-23T01:24:54.670Z",
      "createdAt": "2020-02-23T01:24:54.670Z",
      "name": "color",
      "label": "Color",
      "type": "string",
      "fieldType": "text",
      "groupName": "car_information",
      "displayOrder": -1,
      "calculated": false,
      "externalOptions": false,
      "archived": false,
      "hasUniqueValue": false,
      "hidden": false,
      "modificationMetadata": {
        "archivable": true,
        "readOnlyDefinition": false,
        "readOnlyValue": false
      },
      "formField": false
    },
    {
      "updatedAt": "2020-02-23T01:24:54.667Z",
      "createdAt": "2020-02-23T01:24:54.667Z",
      "name": "mileage",
      "label": "Mileage",
      "type": "number",
      "fieldType": "number",
      "groupName": "car_information",
      "displayOrder": -1,
      "calculated": false,
      "externalOptions": false,
      "archived": false,
      "hasUniqueValue": false,
      "hidden": false,
      "modificationMetadata": {
        "archivable": true,
        "readOnlyDefinition": false,
        "readOnlyValue": false
      },
      "formField": false
    },
    {
      "updatedAt": "2020-02-23T01:24:54.667Z",
      "createdAt": "2020-02-23T01:24:54.667Z",
      "name": "price",
      "label": "Price",
      "type": "number",
      "fieldType": "number",
      "groupName": "car_information",
      "displayOrder": -1,
      "calculated": false,
      "externalOptions": false,
      "archived": false,
      "hasUniqueValue": false,
      "hidden": false,
      "modificationMetadata": {
        "archivable": true,
        "readOnlyDefinition": false,
        "readOnlyValue": false
      },
      "formField": false
    },
    {
      "updatedAt": "2020-02-23T01:24:54.667Z",
      "createdAt": "2020-02-23T01:24:54.667Z",
      "name": "make",
      "label": "Make",
      "type": "string",
      "fieldType": "text",
      "groupName": "car_information",
      "displayOrder": -1,
      "calculated": false,
      "externalOptions": false,
      "archived": false,
      "hasUniqueValue": false,
      "hidden": false,
      "modificationMetadata": {
        "archivable": true,
        "readOnlyDefinition": false,
        "readOnlyValue": false
      },
      "formField": false
    }
  ],
  "associations": [
  {
    "id": "1",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "2-529881",
    "toObjectTypeId": "0-1",
    "name": "car_to_contact"
  },
  {
    "id": "2",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "0-1",
    "toObjectTypeId": "2-529881",
    "name": "car_to_contact"
  },
  {
    "id": "13",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "2-529881",
    "toObjectTypeId": "0-27",
    "name": "car_to_task"
  },
  {
    "id": "14",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "0-27",
    "toObjectTypeId": "2-529881",
    "name": "car_to_task"
  },
  {
    "id": "15",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "2-529881",
    "toObjectTypeId": "0-46",
    "name": "car_to_note"
  },
  {
    "id": "16",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "0-46",
    "toObjectTypeId": "2-529881",
    "name": "car_to_note"
  },
  {
    "id": "7",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "2-529881",
    "toObjectTypeId": "0-48",
    "name": "car_to_call"
  },
  {
    "id": "8",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "0-48",
    "toObjectTypeId": "2-529881",
    "name": "car_to_call"
  },
  {
    "id": "11",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "2-529881",
    "toObjectTypeId": "0-51",
    "name": "car_to_conversation_session"
  },
  {
    "id": "12",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "0-51",
    "toObjectTypeId": "2-529881",
    "name": "car_to_conversation_session"
  },
  {
    "id": "9",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "2-529881",
    "toObjectTypeId": "0-49",
    "name": "car_to_email"
  },
  {
    "id": "10",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "0-49",
    "toObjectTypeId": "2-529881",
    "name": "car_to_email"
  },
  {
    "id": "5",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "2-529881",
    "toObjectTypeId": "0-47",
    "name": "car_to_meeting_event"
  },
  {
    "id": "6",
    "createdAt": null,
    "updatedAt": null,
    "fromObjectTypeId": "0-47",
    "toObjectTypeId": "2-529881",
    "name": "car_to_meeting_event"
  }
 ]
}

After creating the object schema, CarSpot makes sure to note the new object's {objectTypeId} field, as they'll use this for fetching and updating the object later. They can also use the {fullyQualifiedName} value, if they prefer.

Creating a custom object record

With the custom object created, CarSpot can now create records on the object for each car in their inventory.

They'll create their first car by making a POST request to /crm/v3/objects/2-3465404 with the following request body:

JSON
// Example POST request to https://api.hubspot.com/crm/v3/objects/2-3465404
{
  "properties": {
    "condition": "used",
    "date_received": "1582416000000",
    "year": "2014",
    "make": "Nissan",
    "model": "Frontier",
    "vin": "4Y1SL65848Z411439",
    "color": "White",
    "mileage": "80000",
    "price": "12000",
    "notes": "Excellent condition. No accidents."
  }
}

The response for this API call would look similar to:Copy all

JSON
// Example response body
{
  "id": "181308",
  "properties": {
    "color": "White",
    "condition": "used",
    "make": "Nissan",
    "mileage": "80000",
    "model": "Frontier",
    "vin": "4Y1SL65848Z411439",
    "notes": "Excellent condition. No accidents.",
    "price": "12000",
    "year": "2014",
    "date_received": "1582416000000"
  },
  "createdAt": "2020-02-23T01:44:11.035Z",
  "updatedAt": "2020-02-23T01:44:11.035Z",
  "archived": false
}

With the record created, they can use the id value to later associate the car with an existing contact.

If they wanted to later retrieve this record along with specific properties, they could make a GET request to https://api.hubapi.com/crm/v3/objects/2-3465404/181308portalId=1234567&properties=year&properties=make&properties=model

Associating the custom object record to a contact

Using the ID of the new car record (181308) and a contact ID (51), CarSpot can associate the car record with a contact. They'll create this association by making a PUT request to /crm/v3/objects/{objectType}/{objectId}/associations/{toObjectType}/{toObjectId}/{associationType}

Using the above IDs, the request URL will be constructed as follows:

https://api.hubspot.com/crm/v3/objects/2-3465404/181308/associations/contacts/51/75

Defining a new association

CarSpot now wants to start tracking post-sale services for their cars. To do so, they'll use HubSpot tickets to log any maintenance performed.

To allow associations between cars and tickets, they'll create a new association by making a POST request to /crm/v3/schemas/2-3465404/associations with the following request body:

JSON
// Example POST request to https://api.hubspot.com/crm/v3/schemas/2-3465494/associations
{
"fromObjectTypeId": "2-3465404",
"toObjectTypeId": "ticket"
"name": "car_to_ticket"
}

The response for this API call would look similar to:Copy all

JSON
// Example response
{
  "id": "121",
  "createdAt": "2020-02-23T01:52:12.893826Z",
  "updatedAt": "2020-02-23T01:52:12.893826Z",
  "fromObjectTypeId": "2-3465404",
  "toObjectTypeId": "0-5",
  "name": "car_to_ticket"
}

When creating a new association between two custom objects, specify the custom objects by their objectTypeId in the toObjectTypeId field. For standard objects, you can identify them by name or use the following values: 

  • Contact: 0-1
  • Company: 0-2
  • Deal: 0-3
  • Ticket: 0-5

Defining a new property

As they continue to track maintenance, CarSpot sees an opportunity to bundle maintenance services into packages. To track these maintenance packages on individual car records, they'll create a new enumeration property containing the available packages.

To define a new property, they'll make a POST request to /crm/v3/properties/2-3465404 with the following request body:

JSON
// Example POST request to https://api.hubspot.com/crm/v3/properties/2-3465404
{
  "groupName": "car_information",
  "name": "maintenance_package",
  "label": "Maintenance Package",
  "type": "enumeration",
  "fieldType": "select",
  "options": [
    {
      "label": "Basic",
      "value": "basic"
    },
    {
      "label": "Oil change only",
      "value": "oil_change_only"
    },
    {
      "label": "Scheduled",
      "value": "scheduled"
    }
  ]
}

The response for this API call would look similar to:Copy all

JSON
// Example response
{
  "updatedAt": "2020-02-23T02:08:20.055Z",
  "createdAt": "2020-02-23T02:08:20.055Z",
  "name": "maintenance_package",
  "label": "Maintenance Package",
  "type": "enumeration",
  "fieldType": "select",
  "groupName": "car_information",
  "options": [
    {
      "label": "Basic",
      "value": "basic",
      "displayOrder": -1,
      "hidden": false
    },
    {
      "label": "Oil change only",
      "value": "oil_change_only",
      "displayOrder": -1,
      "hidden": false
    },
    {
      "label": "Scheduled",
      "value": "scheduled",
      "displayOrder": -1,
      "hidden": false
    }
  ],
  "displayOrder": -1,
  "calculated": false,
  "externalOptions": false,
  "archived": false,
  "hasUniqueValue": false,
  "hidden": false,
  "modificationMetadata": {
    "archivable": true,
    "readOnlyDefinition": false,
    "readOnlyValue": false
  },
  "formField": false
}

In addition, they want this property to appear in the sidebar of each car record so that the information is readily available to their sales reps and technicians. To do this, they'll add the property to secondaryDisplayProperties by making a PATCH request to /crm/v3/schemas/2-3465404 with the following request body: 

JSON
// Example POST request to https://api.hubspot.com/crm/v3/schemas/2-3465404
{
  "secondaryDisplayProperties": [
    "maintenance_package"
  ]
}

The response for this API call would look similar to:Copy all

JSON
// Example response
{
  "id": "3465404",
  "createdAt": "2020-02-23T01:24:54.537Z",
  "updatedAt": "2020-02-23T02:12:24.175874Z",
    "labels": {
    "singular": "Car",
    "plural": "Cars"
  },  
 "requiredProperties": [
    "year",
    "model",
    "vin",
    "make"
  ],
  "searchableProperties": [
    "year",
    "model",
    "vin",
    "make"
],
 "primaryDisplayProperty": "model",
  "secondaryDisplayProperties": [
    "maintenance_package"
  ],
  "portalId": 1234567,
  "name": "car"
}

Now, when a technician opens a contact record that has an associated car, the property will be displayed in the custom object card in the sidebar:

Screen Shot 2020-03-06 at 11.08.41 AM

As CarSpot continues to use HubSpot, they'll likely find ways to refine and expand this custom object and more using HubSpot's API. They might even decide to build dynamic pages using their custom object data.


Was this page helpful? *
This form is for feedback on our developer docs. If you have feedback on the HubSpot product, please share it in our Idea Forum instead.