Making requests
To retrieve data using HubSQL, make aPOST request to /analytics/hubsql/2027-03-beta/query:
- Include your SQL query as a string in the
queryparameter in the request body. - You can optionally include a
pageSizeparameter to specify the number of entries returned in each page of results (note that ifpageSizeis omitted, the response will default to a page size of 10 entries).
query parameter cannot be left empty.
The response includes up to three fields, detailed in the table below:
The code block below demonstrates an example response:
Authentication
Both OAuth and static auth tokens are supported, along with service keys. Depending on the authorization type, property access permissions configured in your account may be enforced:- OAuth: property access permissions are enforced. If a user doesn’t have view access to a property, querying that property returns
403 INSUFFICIENT_PERMISSIONSwith a message listing the restricted properties. - Static auth and service keys: property access permissions are not enforced. All properties are queryable regardless of per-user restrictions.
Scopes
When retrieving CRM object data, your app must be authorized with the read scope that corresponds to each object type your query references. For example, to queryOBJECT.DEAL, you’d need to authorize the crm.objects.deals.read scope.
To query for events, the business-intelligence scope is required.
Consult the scopes reference article for all available scopes.
Pagination
HubSQL supports cursor-based pagination via theafter and pageSize fields you can include in your request:
- The
afterproperty, also known as the “cursor”, is a Base64 URL-safe encoded token. - The
pageSizeproperty is an optional query parameter that controls the number of rows returned per page, up to a maximum of 100 rows.- If
pageSizeis omitted, it will default to 10 rows. - If the
pageSizeexceeds theLIMITprovided in yourquery, the effective page size is capped at theLIMITvalue.
- If
- Aggregation queries (
GROUP BY,COUNT,SUM, etc.) do not support pagination.
- Send your initial request with a
queryand optionalpageSizein the request body. Do not includeafterin this initial request. - Check if the response includes
paging.next.after, which indicates that additional results are available. - Send another request with the same
queryandpageSizein the request body, but include an additionalafterproperty set to the corresponding cursor value from the previous response. - Repeat steps 2 and 3 until the response no longer includes
paging.next.after.
Data sources
All HubSQL queries must include a data source, which indicates the data type and associated properties you’re requesting. The syntax and supported data sources are detailed in the sections below.Data source resolution
Data sources are specified using the SQL-style format{SCHEMA}.{TABLE}.
- Currently,
OBJECTandEVENTare the only supported values forSCHEMA. - If
SCHEMAis omitted, the query will default toOBJECTas the schema.
OBJECT
UseOBJECT.{TABLE} to query for CRM data, where TABLE corresponds to the object type you want to retrieve, such as DEAL.
The TABLE can be provided in two different formats:
- Fully-qualified name (FQN): the singular name of an object type in your account (e.g.,
DEAL,CONTACT, etc). - Object type ID: the
objectTypeIdof an object, provided within quotes (e.g.,"0-1"for contacts,"0-3"for deals,"2-12345"for a custom object with anobjectTypeIdof 12345). For example,OBJECT."0-1"would be the full data source you’d need to include for querying contact data. Refer to this list of all object type ID values.
EVENT
UseEVENT.{TABLE} to query for event data, where TABLE corresponds to the event type, such as e_ad_interaction.
The TABLE can be provided in two different formats:
- Fully-qualified name (FQN): the singular name of an event type in your account (e.g.,
EVENT.e_ad_interaction,EVENT.pe123_my_custom_event, etc). - Event type ID: the numeric type ID of an event provided within backticks.
- For example,
`EVENT.`4-1553675`would correspond toe_ad_interaction. For an account-specific custom event, the identifier string would resemble:`EVENT.`6-1234567`. - You can also query for app events using backticks or double-quotes, but they may need to be escaped using backslashes. For example,
EVENT.\"ae1158877_integrators-timeline-event-type-id-12672\".
- For example,
Supported data sources and property types
The following standard CRM objects are currently supported as data sources during this phase of the beta:- App objects are supported using the format
1-{ObjectTypeId} - Custom objects are supported using the format
2-{ObjectTypeId}
LEFT JOIN clause.
All standard and custom events are supported when querying for EVENT, as well as app events.
If you attempt to query an unsupported data source, you’ll receive a DATA_SOURCE_NOT_SUPPORTED error in the response.
Properties
Properties are requested as SQL-style columns in your query.- Property types for a specific object can be retrieved and managed using the properties API.
- Event property types can be retrieved using the events API.
Querying for properties
Object or event properties in your query can be specified in a fully qualified format (e.g.,DEAL.dealname).
Bare names (e.g., dealname) are supported for properties referenced by the FROM clause, but cannot be used for any associated objects referenced by the JOIN clause.
Property type response formats
All property types you request in your query are returned as strings. The table below details how each property type is serialized:
If a requested property type is not populated, it will be returned as
null.
Syntax
HubSQL supports standard SQL syntax, with some limitations. Each of the supported clauses are listed in the sections below, along with any associated caveats to keep in mind as you write your queries.SELECT
Provide property type names, functions, or aliases as columns in your query. You can useSELECT * in your query, but the rows in the resulting response will only include the hs_object_id property. Usage of SELECT * is only supported for objects, and cannot be used when querying for event data.
Arithmetic expressions (e.g.,
amount * 1.1) and usage of CASE/WHEN are not currently supported.FROM
Specify the data source to retrieve CRM data from, using theSCHEMA.TABLE format.
You can only retrieve data from one table at a time.
Referencing multiple tables (e.g.,
FROM OBJECT.DEAL, OBJECT.CONTACT`), writing subqueries, or including table aliases are not currently supported.JOIN
Combine records from twoOBJECT tables based on their CRM associations using the LEFT JOIN clause.
For example, the following query would return deal names with their associated contacts, including their first name and their email address:
ON clause, which will result in the default association being used. To specify a specific association path, check out the ON section below.
The following restrictions apply to joining tables:
JOIN type: only LEFT JOIN is currently supported. Using INNER JOIN, RIGHT JOIN, FULL JOIN, and CROSS JOIN will be rejected.
Schema: both tables must use the OBJECT schema. EVENT tables cannot be joined.
Self-joins: each table may appear at most once in the combined query.
Subqueries in JOIN: only plain table references are supported.
Column qualification
Unqualified column names (e.g.dealname) resolve against the primary table. Columns from the joined table must be qualified with the table’s FQN or an alias:
ON clause
TheON clause specifies which association path to traverse:
Check out the examples in the tabs below for guidance on using named associations or numeric combined association type ID:
- Named association
- Numeric combined association type ID
ON d.id = c.id) are not supported. Only string literals will be accepted.
WHERE
Filter on object or event properties. The property type must precede the operator of yourWHERE clause.
The supported operators are detailed in the table below.
Keep the following caveats in mind when using the
WHERE clause:
- If nesting multiple
WHEREclauses, you can include up to fiveORgroupings (i.e., a filter group), with a maximum of 18 total individual filters. - Do not include
= NULL, and instead opt for theIS NULLoperator. - Using
LIKEwith a leading wildcard is not supported (e.g.,dealname LIKE ‘%corp’). - When using
NOT LIKE, you should only use the “contains” format:%pattern%is supported. The prefix form,NOT LIKE 'Acme%'will be rejected. - When using the
BETWEENoperator, both bounds must be the same type (e.g., two numbers, or two dates inYYYY-MM-DDformat). Mixing types throws an error. NOT BETWEENinternally expands to twoORconditions. BecauseORcan’t sit insideAND,NOT BETWEENcan only appear at the top level of theWHEREclause or directly under a top-levelOR. For example, the followingWHEREclause is not supported:
- While you can use
NOTon a single predicate (e.g.,NOT dealstage = 'closedlost'is equivalent to using!=), usage ofNOTwith compound conditions is not supported. For example, theWHEREclause below cannot be used, and should instead be rewritten by negating each condition individually using positive operators:
Using logical operators
When using logical operators, theWHERE clause must be in disjunctive normative form: OR cannot be nested inside an AND group, and should instead be rewritten to have a top-level OR that consist of one (or more) AND groups.
For example, all of the following WHERE clauses are valid:
WHERE clause below is invalid:
IN:
Filtering EVENT data
When querying forEVENT data, keep the following caveats in mind when filtering based on dates:
- To filter events based on the date they occurred, use the
occurredAtproperty.- If you omit an
occurredAtfilter, the query will default to retrieve the last 7 days of event data. - The maximum
occurredAtspan is 90 days. - The end of the range is capped at the end of the current day.
occurredAtfilters cannot be combined withOR. Instead, useANDto constrain the time range.
- If you omit an
- Relative date filters, such as
PREVIOUS_PERIODorCURRENT_PERIOD, as well as usage ofDATE_TRUNC, are only supported when using theoccurredAtevent property. As an alternative, you can use date literals instead.
GROUP BY
Group matching records that have the same values into summary rows. For example, the following query would group matching deals by their deal stage:GROUP BY:
- Use bare property names as the column to a
GROUP_BYclause. Column aliases are also allowed. - Every non-aggregate column in SELECT must appear in GROUP BY (and vice-versa).
- At most 2 GROUP BY columns.
HAVINGis not supported, and any conditions should instead be moved to aWHEREclause.
ORDER BY
Sorts matching records in a specific order. Available values areASC (ascending order, which is the default), or DESC (descending order).
The behavior of ORDER BY depends on whether you’re using an aggregate or non-aggregate query:
- Aggregate: when using any
GROUP BYor aggregate function,ORDER BYmust reference aSELECTalias. Your query is limited to a maximum of 1ORDER BYproperty.
- Non-aggregate: any valid property name can be referenced. Your query can include up to 100
ORDER BYproperties.
ORDER BY with EVENT queries:
- Search queries: only the
occurredAtproperty is supported. IfORDER BYis omitted from your query, search results default to ascending by theoccurredAtproperty. - Aggregate queries: a maximum of one sort column is allowed (metric or dimension).
LIMIT
Restrict the number of matched records.- If omitted, the default maximum is 10 rows (or the custom value you specified using the
pageSizerequest body parameter). - The maximum
LIMITvalue is 10,000 rows for queries without an aggregation function. When your query includes a aggregate function, the maximumLIMITis 500 rows. Note that theLIMITis distinct from thepageSizeparameter used for pagination, which has a separate maximum of 100 rows per page.
Identifiers and literals
Values included in your query are case-insensitive. Any identifiers containing hyphens should be wrapped in double-quotes (e.g.,"my-custom-property").
The conventions below apply based the identifier type:
- String literals use single quotes (‘closedwon’).
- Date and datetime literals: use quoted strings in
YYYY-MM-DDorYYYY-MM-DDTHH:MM:SSZ formats( ‘2024-01-01’ and ‘2024-05-17T00:00:00Z’) - Booleans: use lower-cased, unquoted boolean literals (
trueorfalse). - Numerics: both integers or decimals are allowed (
1000,3.14).
Functions
HubSQL supports aggregate, scalar, and filter functions.Aggregate functions
The table below outlines the supported aggregate functions and their supported properties. Note that forEVENT queries, you cannot use occurredAt for any aggregate function.
The
COUNT(DISTINCT column) function is approximate. The COUNT(DISTINCT column) and MEDIAN(column) aggregate functions cannot be used with GROUP BY.
The resulting value in the response follows the format:
{auto-generated-key}_{property_name} (e.g., sum_amount).
For example, the following query would provide a ranked list of deal stages from most deals to fewest, with the total pipeline value per stage:
Scalar functions
Currently, only theDATE_TRUNC function is supported in queries to reduce a date or timestamp based on the provided time_unit.
The following caveats apply to usage of the
DATE_TRUNC function:
- Supported
WHEREoperators are:=,\>,\>=,\<,\<=,BETWEEN, andNOT BETWEEN. - A property can only be wrapped in
DATE_TRUNConce per query. - If
DATE_TRUNC(property, time_unit)appears inSELECT, theGROUP BYmust use the same granularity for that column (e.g. ‘month’ inSELECTrequires ‘month’ inGROUP BY)
Filter functions
The following functions can be used to filter matching records based on date or datetime properties. These functions must precede the= operator of a WHERE operator.
Filter functions require date or datetime properties. Using them on an enumeration, string, or numeric property returns an error.
The time period boundary depends on the property type:
- Date properties: boundaries are calculated using the account’s configured timezone.
- Datetime properties: boundaries are calculated in UTC.
Limits
Usage of HubSQL is subject to limits on both query complexity and the rate at which you send queries in a given time period.Query limits
Exceeding any of these caps returns aQUERY_TOO_COMPLEX error with a specific message.
Rate limits
The limits below are enforced per-account and per-app:
Exceeding a limit returns
429 RATE_LIMIT_EXCEEDED with the policy name and a retry-after hint in the response body. For a 429, use exponential backoff with jitter starting at 1 second. For a 500, retry up to 3 times before contacting support.
Errors
Errors will follow the standard HubSpot API response format:category and subCategory values are detailed in the table below: