HubDB
Access and test APIs in beta.
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 updatePATCH
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 |
|
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 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 |
|
Set this to true to use the page for dynamic pages. |
Columns |
|
A list of column definitions that will be used for the table. |
Allow public API access |
|
Set this to true to allow public API access without any auth. |
Allow child tables |
|
Set this to true to allow child tables for each row. |
Enable dynamic pages for child tables |
|
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 |
|
The internal name of the column. This name cannot be changed once the column is created |
Label |
|
Optional - The label for the column. This is what users will see when editing the table in HubSpot. |
Type |
|
The data type of the column. Must be one of
|
Options |
|
If the column is the |
Example request for table creation
//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 |
|
If the table is enabled for dynamic pages, this is the path suffix used for the page for this row. |
Page title |
|
If the table is enabled for dynamic pages, this is the HTML title used for the page for this row. |
Child table id |
|
Specify the child table id for multi-level dynamic pages. |
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 |
While updating existing rows, include "id " field in the input object.
Example request for row creation
//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"
}
Filtering & sorting table rows
Filters are applied as query parameters, by adding the column name, followed by two underscores (_), and then the operator. For example, if you have a number column named 'bar', you can filter the results to only include rows where the 'bar' column is greater than 10 using this parameter: &bar__gt=10. Any number of filters can be included as query parameters in the request URL. All filters are ANDed together. ORing filters are not currently supported.
Operators can only be applied to specific column types. When passing values for MULTISELECT columns, the ids or names should be separated by commas (e.g. multiselect_column__contains=1,2) For the purposes of these filters, the built in column `hs_id`is a NUMBER column, the `hs_created_at` column is a DATETIME, and the `hs_path` and `hs_name` columns is a TEXT column.
For DATETIME filters, you can use relative dates in place of timestamps in order to specify a value relative to the current time. For example, -3h would correspond to the timestamp 3 hours before now, whereas 10s would correspond to 10 seconds in the future. Supported timeunits are ms (milliseconds), s (seconds), m (minutes), h (hours), d (days). Current time can be used by specifying a zero value: 0s
Field name |
Operator |
Description |
Equals |
eq (or none) |
All column types This filter is applied if no operator is used &example_column=value When used with MULTISELECT columns, returns rows that exactly match supplied values |
Not equal |
ne |
All column types |
Contains | contains |
TEXT, RICHTEXT, MULTISELECT When used with MULTISELECT columns, returns rows that contain all of the supplied values. |
Less than |
lt |
NUMBER, DATE, DATETIME |
Less than or equal |
lte |
NUMBER, DATE, DATETIME |
Greater than |
lte |
NUMBER, DATE, DATETIME |
Greater than or equal |
gte |
NUMBER, DATE, DATETIME |
Null | is_null |
All column types, except BOOLEAN This filter does not require a value (&example_column__is_null=) |
Not null |
not_null |
All column types, except BOOLEAN This filter does not require a value (&example_column__not_null=) |
Like |
like |
TEXT, RICHTEXT |
Not like |
not_like |
TEXT, RICHTEXT |
Contains (case insensitive) |
contains |
TEXT, RICHTEXT |
Starts with |
startswith |
TEXT, RICHTEXT |
In |
in |
NUMBER, SELECT, MULTISELECT Returns rows where the column includes at least one of the passed options. When there is no other Order By in the query parameter, the results will be sorted in the order in which values are specified in the 'in' operator. |
Sorting can also be applied as query parameters. You can specify the column name as value to the query parameter `sort` and it returns the rows in the natural order of the specified column. You can reverse the sort by adding a - to the column name: sort=-bar. You can include this parameter multiple times to sort by multiple columns.
In addition to sorting by a column, there are three functions that can be used:
- geo_distance(location_column_name, latitude, longitude): Takes the name of a location column and coordinates, returns the rows ordered by how far away the values of the specified location column are from the provided coordinates.
- length(column_name): Takes the name of a column, returns the rows ordered by the length of the column value (calculated as a string)
- random(): Returns the rows in random order.
These functions also support reverse ordering: sort=-geo_distance(location_column,42.37,-71.07) returns the items that are the farthest away first.
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 |
|
The number of header rows that should be skipped over. Defaults to |
separator |
|
Column delimiter in the CSV file. Default is |
idSourceColumn* |
|
The index of the column in the source file containing the row’s |
resetTable |
|
Defaults to |
nameSourceColumn |
|
The index of the column in the source file containing the row’s |
pathSourceColumn |
|
The index of the column in the source file containing the row’s |
childTableSourceColumn |
|
The index of the column in the source file containing the row’s |
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: |
primaryKeyColumn |
|
The name of a column in the target HubDB table to use for row deduplication. |
encoding |
|
Encoding type. (utf-8, ascii, iso-8859-2, iso-8859-5, iso-2022-jp, windows-1252) |
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.
- if the rows in the csv file does not have a row id column or row id is specified as
- 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
//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:
//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;