HubDB

This API is in beta.

Please note: This API is currently in public beta and is subject to change based on testing and feedback. By using these endpoints you agree to adhere to our Developer Developer Beta Terms of Use. You also acknowledge and understand the risk associated with testing an unstable API. 

 

This API is currently under development. For the latest stable version check out this page

HubDB is a relational data store representing data as rows, columns, and cells in a table, much like a spreadsheet.

Data in a HubDB table can be accessed from HubSpot pages using HubL or the JSON REST APIs. Endpoints that support GET also support CORS, so you can access the data in a table client-side using JavaScript and an account ID (often called Hub ID). Note: This only applies to GET methods. Other methods and the GET all tables API require authentication, and will not support CORS.

Modifying HubDB tables

HubDB tables can be modified in HubSpot, making it easy for anyone to add or modify data in those tables. You can also use the API for this.

For more details and information on using data in a HubDB table on a HubSpot site, click here.

Rate limits

HubDB API requests have different rate limits, depending on the type of request:

  • Any GET requests made that don't require authentication (including client-side JavaScript requests) are limited to 10 requests per second. These requests will not count towards the daily limit.
  • All other requests using authentication follow the standard limits.

Changes in V3:

  • Tables should have both name and label. This name cannot be changed once the table is created. Names can only include lowercase letters, digits, and underscores and cannot begin with a number. Both name and label should be unique in the account.
  • API supports both table id and name in the URL paths.
  • GET row endpoints return column name instead of id in values field. Also, POST / PUT / PATCH row endpoints require column name instead of id in values field.
  • Row update PATCH endpoints now accept sparse updates, which means we can specify only the column values that we need to update (whereas we had to specify all the column values in the previous versions). When you update a column with a list of values such as multi-select, you need to specify the list of all the values. In order to delete the value for a column, you need to specify the column with the value as null in the request. 
  • Removed the endpoints to get / update / delete a row cell  in favor of the row update PATCH endpoints.
  • Import endpoint now supports an optional field idSourceColumn along with existing fields in the JSON-formatted options. You can use this field to specify the column in the csv file which contains row ids. To import new rows along with the new values for existing rows, you can simply specify 0 as the row id for the new rows and the valid row ids for the existing columns.  See more details in the Import section below. Also you can use column names or ids in the target field of the column mappings in the JSON-formatted options.
  • Clone endpoint requires a new name and new label.

Draft vs Live Versions

HubDB tables have both draft and live versions and live versions can be published or unpublished. This will allow you to update data in the table, either for page previews or testing or to allow for a manual approval process, without affecting any live pages. Draft data can be reviewed and then pushed live / published by a user working in HubSpot, or via /push-live endpoint of the API. The draft data can also be discarded via /reset endpoint, allowing users to go back to the current live version of the data without disruption.

Creating tables

Tables can have the following fields:

Required fields

How to use

Description

Name

"name":{name}

The internal name of the table. This name cannot be changed once the table is created. Names can only include lowercase letters, digits, and underscores and cannot begin with a number.

Label

"label":{label}

Label of the table. This is what users will see when editing the table in HubSpot.

 

Optional fields

How to use

Description

Use for dynamic pages

"useForPages": false

Set this to true to use the page for dynamic pages.

Columns

"columns":[ {list of columns} ]

A list of column definitions that will be used for the table.

Allow public API access

"allowPublicApiAccess": false

Set this to true to allow public API access without any auth.

Allow child tables

"allowChildTables": false

Set this to true to allow child tables for each row.

Enable dynamic pages for child tables

"enableChildTablePages": false

Set this to true to create dynamic pages for child tables

 

Column

Each column should include the following fields:

Field

How to use

Description

Name

"name":{name}

The internal name of the column. This name cannot be changed once the column is created

Label

"label":{label}

Optional - The label for the column. This is what users will see when editing the table in HubSpot.

Type

"type":{type}

The data type of the column. Must be one of

  • TEXT - A simple text field.
  • RICHTEXT - A text field that supports basic HTML.
  • NUMBER - a number field
  • BOOLEAN - Represented as a checkbox in HubSpot, uses 0 for unchecked and 1 for checked.
  • DATE - Stores a specific date as a millisecond timestamp set to midnight UTC for the specified date.
  • DATETIME - Stores a date and a time as a millisecond timestamp.
  • SELECT - The column can only be set to one of a set of options.
  • MULTISELECT - The column can be set to one or more of a set of options.
  • URL - Stores a URL.
  • LOCATION - Stores a latitude and longitude location.
  • IMAGE - Stores the URL of an image.
  • VIDEO - Stores the player id of the video.
  • FOREIGN_ID - Stores the row id from the referenced table.
  • CURRENCY - Stores the number.

Options

"name":{name} "options": [ {list of options} ]

If the column is the SELECT type, this will be used as the options for the column. Each option must include a name and a type of "option": [{"name":"a", "type":"option"}, {"name":"b", "type":"option"}.

 

Example request for table creation

JSON
//example request
{
 "label": "Test Table",
 "name": "test_table",
 "columns": [
 {
   "name": "text_column",
   "label": "Text Column",
   "archived": false,
   "type": "TEXT"
 },
 {
   "name": "number_column",
   "label": "Number Column",
   "archived": false,
   "type": "NUMBER"
 },
 {
   "name": "multiselect",
   "label": "Multi Select Column",
   "archived": false,
   "options": [
   {
     "id": "1",
     "name": "Option 1",
     "type": "option"
   },
   {
     "id": "2",
     "name": "Option 2",
     "type": "option"
   }
   ],
   "type": "MULTISELECT"
 }
 ],
 "useForPages": true,
 "allowChildTables": true,
 "enableChildTablePages": false,
 "dynamicMetaTags": {
 },
 "allowPublicApiAccess": false
}

While updating existing tables or columns, include the "id " field as well.

Creating table rows

Rows should include the following fields:

Optional fields

How to use

Description

Path

"path": “example path”

If the table is enabled for dynamic pages, this is the path suffix used for the page for this row.

Page title

"name": “example title”

If the table is enabled for dynamic pages, this is the HTML title used for the page for this row.

Child table id

"childTableId: 1902373

Specify the child table id for multi-level dynamic pages.

Values

"values": [ {list of cell values} ]

A list of values for the cells in the row. Each entry requires a column name you’d get when pulling the table details and the value being set for that column. For example, when setting a column test and type TEXT to use the value 'test value’, use "test": "test value". See below for more details for the values used by specific column types.

 

While updating existing rows, include "id " field in the input object.

Example request for table creation

JSON
//example request

{
 "values": {
   "text_column": "sample text value",
   "number_column": 76,
   "rich_text_column": "<strong>This is a styled paragraph.</strong>",
   "date_column": 1591228800000,
   "date_time_column": 1604450520000,
   "boolean_column": 1,
   "select_column": {
      "id": "1",
      "name": "option 1",
      "type": "option"
    },
   "multiselect_column": [
   {
     "id": "1",
     "name": "Option 1",
     "type": "option"
   },
   {
     "id": "2",
     "name": "Option 2",
     "type": "option"
   }
   ],
   "url_column": "https://www.hubspot.com/marketing",
   "video_column": 3392210008,
   "image_column": {
      "url": "https://f.hubspotusercontentqa00.net/hubfs/99992002/image3%20(1).jpg",
      "width": 1600,
      "height": 900,
      "type": "image"
    },
    "foreign_id_column": [
      {
        "id": "4364402239",
        "type": "foreignid"
      },
      {
        "id": "4364402240",
        "type": "foreignid"
      }
    ]
 },
 "path": "test_path",
 "name": "test_title",
 "childTableId": "1902373"
}

Importing tables

Import endpoint takes a multi-part POST request. The first part will be a set of JSON-formatted options for the import and you can specify this with the name as " config ".  The second part will be the CSV file you want to import and you can specify this with the name as " file ".

Include the following fields as a JSON string in the JSON-formatted options.



Field name

How to use

Description

skipRows

"skipRows":{skipRows}

The number of header rows that should be skipped over. Defaults to 1 (skipping the first row and treating it as a header). Set this to 0 if all of the rows are valid data.

separator

"separator":{separator}

Column delimiter in the CSV file. Default is ,

idSourceColumn*

"idSourceColumn":{idSourceColumn}

The index of the column in the source file containing the row’s ID(hs_id). Use this in conjunction with resetTable to preserve the row ids during imports. (The previous versions of the API create new row ids during every import even if resetTable is true and this version attempts to fix the issue). This is optional and you can ignore this during the first time you insert data into a table.

resetTable

"resetTable":{resetTable}

Defaults to false. If false, the rows will be inserted / updated without removing anything from the table. If true, the CSV data will replace all data in the table. If a row's id is present in the CSV, the row in the table will be replaced. If a row's id is not present in the CSV, the row will be removed from the table. 

nameSourceColumn

"nameSourceColumn":{nameSourceColumn}

The index of the column in the source file containing the row’s name.

pathSourceColumn

"pathSourceColumn":{pathSourceColumn}

The index of the column in the source file containing the row’s path.

childTableSourceColumn

"childTableSourceColumn":{childTableSourceColumn}

The index of the column in the source file containing the row’s childTableId.

columnMappings

"columnMappings":{list of columnMappings}

A list of mappings for the columns in the source file to the columns in the destination HubDB table. Each mapping must have the following format: {"source":1,"target”:"column_name"} where source refers to the column index in the source file and target refers to the name of the HubDB table column. You can get the name of the columns by getting the details for the table.

primaryKeyColumn

"primaryKeyColumn":{primaryKeyColumn}

The name of a column in the target HubDB table to use for row deduplication.

encoding

"encoding":{encoding}

Encoding type. (utf-8, ascii, iso-8859-2, iso-8859-5, iso-2022-jp, windows-1252)

format

"format":{format}

Unused. Only CSV is supported.

We have two options while importing the data into the table: Add Rows and Reset

  • With reset table option (can be specified as "resetTable":true in the  JSON-formatted options)
      • if the rows in the csv file does not have a row id column or row id is specified as 0, those rows will be inserted with the new row ids generated.
      • if the row ids in the csv file already exists in the target table, the existing rows in the table will be updated with the new values from the input file.
      • if the table has rows but the input csv file does not have those row ids, those rows will be deleted from the target table.
      • if the row ids in the input csv file do not exist in the target table, those rows will be inserted with the new row ids generated and the row ids given in the input file will be ignored.
      • if the input csv file does not contain the row id column at all, all the rows will be deleted from the target table and the rows from the input file will be inserted with the new row ids generated.
  • With add rows option (can be specified as "resetTable":false in the  JSON-formatted options)
      • if the row ids in the csv file already exists in the target table, the existing rows in the table will be updated with the new values from the input file.
      • if the table has rows but the input csv file does not have those row ids, those rows will not be deleted from the target table and those rows will remain unchanged.
      • if the row ids in the input csv file do not exist in the target table, those rows will be inserted with the new row ids generated and the row ids given in the input file will be ignored.
      • if the rows in the csv file does not have a row id column or row id is specified as 0, those rows will be inserted with the new row ids generated.

Example JSON config

JSON
//example config
{
"skipRows":1,
"format":"csv",
"separator":",",
"encoding":"utf-8",
"columnMappings": [
  {"target":1,"source":"text_column"}, 
  {"target":2,"source":"number_column"},
  {"target":3,"source":"multiselect"}
],
"idSourceColumn":1,
"pathSourceColumn":2,
"nameSourceColumn":4,
"childTableSourceColumn":5,
"resetTable":true
}

Example curl command for the import endpoint:

Shell script
//example curl command

curl 'https://api.hubapi.com/cms/v3/hubdb/tables/lesson/draft/import?portalId=99992002&hapikey=apikey'   
-H 'accept: application/json, text/javascript, */*; q=0.01' 
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundaryelAAdi3MTqAK2hrt'  -H 'sec-fetch-site: same-origin'  
-H 'sec-fetch-mode: cors' 
-H 'sec-fetch-dest: empty' 
--data-binary 
$'------WebKitFormBoundaryelAAdi3MTqAK2hrt\r\nContent-Disposition: 
form-data; name="config"\r\n\r\n{"skipRows":1,"format":"csv","separator":",","encoding":"iso-8859-1","columnMappings":[{"target":"name","source":6},{"target":"lesson_order","source":7},{"target":"rich_text","source":8}],"idSourceColumn":1,"pathSourceColumn":null,"nameSourceColumn":null,"childTableSourceColumn":null,"resetTable":true}\r\n------WebKitFormBoundaryelAAdi3MTqAK2hrt\r\nContent-Disposition: form-data; name="file"; filename="sample_input_file.csv"\r\nContent-Type: text/csv\r\n\r\n\r\n------WebKitFormBoundaryelAAdi3MTqAK2hrt--\r\n'
 --compressed;