Custom objects

  • Marketing Hub
    • Enterprise
  • Sales Hub
    • Enterprise
  • Service Hub
    • Enterprise
  • CMS Hub
    • Enterprise
  • Operations Hub
    • Enterprise

In each HubSpot account, there are the standard CRM objects: contacts, companies, deals, and tickets. To represent and organize your CRM data based on your business needs, you can also create custom objects. You can create a custom object in HubSpot, or use the custom objects API to define custom objects, properties, and associations to other CRM objects. 

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

To learn more about creating custom objects, check out the following posts on the HubSpot developer blog:

Please note: custom objects are specific to each account, and depending on your subscription, there are limits on the number of custom objects you can create. Learn more about your limits in the HubSpot Products & Services catalog.

Authentication methods

You can create, read, and update custom objects using one of the following methods of authentication:

Please note: as of November 30, 2022, HubSpot API Keys are being deprecated and are no longer supported. Continued use of HubSpot API Keys is a security risk to your account and data. During this deprecation phase, HubSpot may deactivate your key at any time.

You should instead authenticate using a private app access token or OAuth. Learn more about this change and how to migrate an API key integration to use a private app instead.

Create a custom object

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 schema 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.
  • The name can only contain letters, numbers, and underscores.
  • The first character of the name must be a letter.
  • Long labels may be cut off in certain parts of the product.

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


The properties you define in the request body will be used to store information on individual custom object records.

Please note: you can have up to 10 unique value properties for each custom object in your HubSpot account.

You'll use your defined 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.
    • 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
    • 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.


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: 

// 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/p_{object_name}
  • /crm/v3/schemas/{fullyQualifiedName}. You can find an object's

    fullyQualifiedName in its schema, which is derived from p{portal_id}_{object_name}. You can find your account's portal ID using the account information API.

For example, for an account with an ID of 1234 and an object named lender, your request URL could look like any of the following:

Retrieve custom object records

You can also retrieve a custom object's records.

  • To retrieve a specific record by its record ID value, make a GET request to crm/v3/objects/{objectType}/{recordId}.
  • To retrieve multiple records, make a POST request to crm/v3/objects/{objectType}/batch/read. In your request, you can retrieve records by their record ID (hs_object_id), or by a custom unique identifier property. By default, the id values in the request refer to the record ID, so the idProperty parameter is not required when retrieving by record ID. To use a custom unique value property, you must include the idProperty parameter.

For example, to retrieve a batch of custom object records, your request could look like either of the following:

///Example request body for record ID { "properties": [ "petname" ], "inputs": [ { "id": "12345" }, { "id": "67891" } ] }
///Example request body for unique value property { "properties": [ "petname" ], "idProperty": "uniquepropertyexample", "inputs": [ { "id": "abc" }, { "id": "def" } ] }

Update existing custom objects

To update an object's schema, make a PATCH request to{objectTypeId}.

Once your custom object is defined:

  • The object's name and labels (singular and plural) cannot be changed.
  • The requiredProperties, searchableProperties, primaryDisplayProperty, and secondaryDisplayProperties can be changed by updating the object's schema. To set a new property as a required, searchable, or display property, you need to create the property prior to updating the schema.
  • You can create and edit custom object properties either in HubSpot or via 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:

// 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 add a description to provide context about how to use the object, and 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

// Example POST request to { "name": "cars", "description": "Cars keeps track of cars currently or previously held in our inventory.", "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" ] }

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:

// Example POST request to { "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

// 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

Associating the custom object record to another record

You can use the ID of the new car record (181308) and the ID of another record to associate a custom object record with a record of another object.

To create an association, make a PUT request to /crm/v3/objects/{objectType}/{objectId}/associations/{toObjectType}/{toObjectId}/{associationType}. If the object relationship is already defined, to determine the associationType value, make a GET request to crm/v3/schemas/{objectType}.

For example, with the contact ID 51 and the association type 75, CarSpot can associate the car record with a contact. Using the above IDs, the request URL will be constructed as follows:

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:

// Example POST request to { "fromObjectTypeId": "2-3465404", "toObjectTypeId": "ticket", "name": "car_to_ticket" }

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

// 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:

// Example POST request to { "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

// 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 }

Now that the property has been created, they want it 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: 

// Example PATCH request to { "secondaryDisplayProperties": [ "maintenance_package" ] }

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

// 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 article helpful?
This form is used for documentation feedback only. Learn how to get help with HubSpot.